테스트 인프라 구축 2. 모니터링 환경 구축

jhkim31·2024년 7월 19일
0

이전 글에서 docker-swarm 으로 docker 클러스터를 구축했다.

이번 글에서는 각 노드들의 상태를 모니터링하기 위한 방법을 다룬다.

모니터링 인프라

내가 원하는 모니터링은

  1. 각 vm의 자원 상태 모니터링
  2. 각 컨테이너의 자원 상태 모니터링
  3. 스프링 부트 톰캣 모니터링
  4. mysql 모니터링

을 원했다.

prometheus

모니터링 툴로는 prometheus와 grafana를 사용하기로 했다.
폴링 방식으로 메트릭을 수집하기 때문에 각 어플리케이션에서는 exporter 만 해주기만 하면 수집이 편리하다. 또한 docker 를 사용하기 때문에 서비스 디스커버리 기능을 사용해 수집 대상을 추상화 할 수 있다는 점또한 사용하는데 큰 이점이 된다.

각 노드는 node-exporter 를 통해 vm 의 상태를 제공해주고, cAdvisor 로 컨테이너 상태를 제공한다.
그리고 스프링 애플리케이션은 actuator 를 통해 jvm 상태를 제공하고, mysql은 mysql-exporter 를 통해 상태를 제공해준다.

이렇게 노출된 데이터를 프로메테우스라는 하나의 중앙 시스템에서 폴링으로 수집할 수 있기 때문에 아키텍쳐면에서나, 관리 측면에서도 간단하다.

docker swarm

네트워크

일반적으로 생성하는 docker 네트워크는 기본적으로 호스트 하나에서만 사용하는 목적으로 생성된다.
하지만 swarm은 여러개의 노드를 통해 통신을 해야하기 때문에 다른 네트워크가 필요하다.

docker swarm에 참가한 노드끼리 통신을 할 수 있는 overlay 네트워크가 필요하고, 다음과 같이 생성한다.

docker network create -d overlay {이름}

생성된 네트워크를 확인해보면 scope이 swarm driver가 overlay 인것을 확인할 수 있다.

stack과 service

docker swarm에는 service 와 stack 이란 단위가 있다.

service 는 오케스트레이션 환경에서 다루는 단위로, 하나의 컨테이너에 대한 서비스를 정의한다.
하나의 서비스에 복제를 통해 여러개의 컨테이너를 띄울 수 있고, 원하는 상태를 설정해 해당 상태가 되도록 명령을 보낼 수 있다. (ex 이미지 업데이트)
동일 네트워크에 속한다면 이 서비스 이름으로 dns를 날릴 수 있으며 단일 진입점을 제공하게 된다. 마치 쿠버네티스의 서비스와 유사하다.

stack 은 여러개의 서비스로 구성된 애플리케이션이며, 여러개의 서비스를 하나의 논리적 단위로 배포하고자 할때 사용한다.
docker-compose 양식으로 stack 을 정의해 배포할 수 있다.

아래는 이번 모니터링에 사용된 파일이다.
서비스 하나씩 분석해보자.

version: "3.9"

services:
  node-exporter:
    image: prom/node-exporter:latest
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    ports:
      - target: 9100
        published: 9100
        protocol: tcp
        mode: host
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points="^/(sys|proc|dev|host|etc)($$|/)"'
    deploy:
      mode: global
    networks:
    - jshop
    restart: unless-stopped

  cadvisor:
    image: google/cadvisor
    deploy:
      mode: global
      labels:
        prometheus-job: cadvisor
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    - /:/rootfs:ro
    - /var/run:/var/run
    - /sys:/sys:ro
    - /var/lib/docker:/bar/lib/docker:ro
    ports:
      - target: 8080
        protocol: tcp
        mode: host

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - /home/jhkim/monitoring/prometheus/data:/prometheus
    - /home/jhkim/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
    - jshop
    deploy:
      placement:
        constraints:
        - node.labels.role == monitoring
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--web.console.libraries=/usr/share/prometheus/console_libraries'
      - '--web.console.templates=/usr/share/prometheus/consoles'
      - '--web.enable-remote-write-receiver'
      - '--enable-feature=native-histograms'
      
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=1234
    volumes:
      - /home/jhkim/monitoring/grafana:/var/lib/grafana
    networks:
    - jshop
    deploy:
      placement:
        constraints:
        - node.labels.role == monitoring
        
networks:
  jshop:
    external: true

node-exporter 서비스

  node-exporter:
    image: prom/node-exporter:latest
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    ports:
      - target: 9100
        published: 9100
        protocol: tcp
        mode: host
    command:
      - '--path.procfs=/host/proc'
      - '--path.sysfs=/host/sys'
      - '--collector.filesystem.ignored-mount-points="^/(sys|proc|dev|host|etc)($$|/)"'
    deploy:
      mode: global
    networks:
    - jshop
    restart: unless-stopped

호스트의 상태를 모니터링 하기 위한 node-exporter 다.
모니터링을 위해 필요한 디렉토리(/proc, /sys, /) 를 마운트 해주고, 실행 명령을 수행해준다.
여기서 exporter 한 호스트의 상태 정보를 prometheus 가 스크래핑 해가서 그라파나에 띄우는 방식이다.

deploy 모드를 글로벌로 설정하게 되면, 각 노드에 하나씩 띄워지게 되고, restart: unless-stopped 설정을 주게 되면 직접 종료하기 전까지 컨테이너가 자동 재시작 하게 된다.

https://hub.docker.com/r/prom/node-exporter

여기를 참고해 작성했다.

cadvisor 서비스

  cadvisor:
    image: google/cadvisor
    deploy:
      mode: global
      labels:
        prometheus-job: cadvisor
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock:ro
    - /:/rootfs:ro
    - /var/run:/var/run
    - /sys:/sys:ro
    - /var/lib/docker:/bar/lib/docker:ro
    ports:
      - target: 8080
        protocol: tcp
        mode: host
    command: -docker_only

각 컨테이너들의 cpu, memory 등을 모니터링 하기 위한 cadvisor 다.
이역시 한 노드당 하나씩 필요하기 때문에 global 노드로 동작하게 된다. 그리고 서비스 디스커버리를 위해 prometheus-job: cadvisor 라는 라벨을 추가로 붙여준다.

이 설정은 아래 링크를 참고해 만들었다.
https://prometheus.io/docs/guides/dockerswarm/

prometheus 서비스

  prometheus:
    image: prom/prometheus
    ports:
      - "9090:9090"
    volumes:
    - /var/run/docker.sock:/var/run/docker.sock
    - /home/jhkim/monitoring/prometheus/data:/prometheus
    - /home/jhkim/monitoring/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    networks:
    - jshop
    deploy:
      placement:
        constraints:
        - node.labels.role == monitoring       

node-exporter, cAdvisor, 데이터 수집을 위한 prometheus 서비스다.

특이사항으로는 - /var/run/docker.sock:/var/run/docker.sock 를 마운트 해준다.

이유는 도커의 서비스 디스커버리를 사용하기 위함이다.

서비스 디스커버리

만약 서비스 디스커버리를 사용하지 않는다면 노드가 추가될때마다 스크래핑 설정에 이 노드를 직접 추가해 줘야 한다.

# 노드 추가전
target : ['192.168.0.1:9100'] 
# 노드 추가후
target : ['192.168.0.1:9100', '192.168.0.2:9100'] 

이런식으로 추가해줘야 하지만, 서비스 디스커버리를 사용해 엔드포인트를 추상화하고 클라이언트에는 이를 통해 엔드포인트를 직접 알필요 없이 사용할 수 있다.

예를들어 prometheus.yml 의 일부를 보면 다음과 같다.

  - job_name: 'node-exporter'
    dockerswarm_sd_configs:
      - host: unix:///var/run/docker.sock
        role: nodes
    relabel_configs:
      - source_labels: [__meta_dockerswarm_node_address]
        target_label: __address__
        replacement: $1:9100

보면 __meta_dockerswarm_node_address 라는 추상화된 소스라벨이 보인다.
이는 docker swarm 에서 동작중인 노드의 주소를 얻을 수 있는 추상화로 이를 통해 직접 노드를 추가할 필요 없이 추상화된 서비스 디스커버리를 사용할 수 있다.

grafana 서비스

  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=1234
    volumes:
      - /home/jhkim/monitoring/grafana:/var/lib/grafana
    networks:
    - jshop
    deploy:
      placement:
        constraints:
        - node.labels.role == monitoring

다양한 데이터들을 수집하고 시각화 하기 위해 띄운 grafana 서비스다.
이역시 특별한 설정은 없고, 네트워크 설정정도만 보면 된다.

docker stack 등록

이제 마스터 노드에서 작성한 파일을 등록해준다.

// master-01
docker stack deploy -c docker-compose.yml monitoring

정상적으로 등록이 된다면 다음과 같은 로그를 확인할 수 있고,

docker ps -a 를 사용해 컨테이너를 확인해 본다면 마스터 노드에는 5개, 그리고 각 노드에는 2개씩 컨테이너가 띄워져 있는것을 확인할 수 있다.

profile
김재현입니다.

0개의 댓글