컨테이너 모니터링으로 투명성 있는 애플리케이션 만들기

jjunhwan.kim·2023년 8월 4일
0

도커

목록 보기
5/6
post-thumbnail

개요

이번 포스트에서는 컨테이너 환경에서 애플리케이션을 모니터링하는 방법을 알아보겠습니다. 프로메테우스를 사용해 애플리케이션에서 측정된 수치를 수집하고 그라파나를 이용해 시각화하는 형태로 사용합니다.

먼저 예제 프로젝트는 이전 포스트에서의 마지막 커밋을 사용하겠습니다. (https://github.com/nefertirii/docker-example/tree/3021a5cac264318ff34b519ed16daefe6017aa08)

프로메테우스 도커 연동

먼저 프로메테우스는 애플리케이션에서 데이터를 수집하여 DB에 저장하는 기능을 제공하는 도구입니다. 프로메테우스도 컨테이너에서 실행될 수 있습니다.

프로메테우스는 애플리케이션 뿐만 아니라 도커 엔진의 측정 값도 추출할 수 있습니다. 이 기능을 사용하려면 도커 엔진 설정에서 측정 값을 공개하도록 설정해야합니다.

도커 엔진을 사용한다면 /etc/docker/daemon.json 파일에 아래 내용을 추가합니다.

"metrics-addr": "127.0.0.1:9323"

도커 데스크탑을 사용한다면 설정에서 도커 엔진 설정에 위의 내용을 추가합니다.

metrics-addr 설정을 적용하고 도커 엔진 또는 도커 데스크탑을 재시작하면 http://localhost:9323/metrics 에서 도커 엔진의 상태 정보를 볼 수 있습니다.

아래와 같이 측정된 상태 정보 값이 텍스트로 출력이 되는데, 프로메테우스 포맷으로 출력된 값입니다. 프로메테우스는 이 값을 수집하면서 타임스탬프 값을 덧붙여 저장하여 시간에 따른 값의 변화를 추적할 수 있습니다.

프로메테우스를 컨테이너에서 실행해보겠습니다. 먼저 프로메테우스 도커 이미지 스크립트를 작성합니다. 버전은 최신 버전인 2.46.0을 사용하고 호스트 컴퓨터의 prometheus.yml 설정파일을 이미지의 프로메테우스 설정 파일 경로인 /etc/prometheus/에 복사합니다.

FROM prom/prometheus:v2.46.0

COPY prometheus.yml /etc/prometheus/prometheus.yml

다음은 설정 파일 prometheus.yml 을 작성합니다. 아래 내용은 프로메테우스 기본 prometheus.yml 파일에 도커를 추가한 내용입니다.job_name: "docker" 라인부터가 추가된 부분입니다. targets 에 도커 엔진이 실행중인 호스트 컴퓨터의 IP 주소와 9323 포트를 입력합니다.

# my global config
global:
  scrape_interval: 15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

# Alertmanager configuration
alerting:
  alertmanagers:
    - static_configs:
        - targets:
          # - alertmanager:9093

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=<job_name>` to any timeseries scraped from this config.
  - job_name: "prometheus"

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: "docker"
    metrics_path: /metrics
    static_configs:
      - targets: ["192.168.0.204:9323"]

이제 설정 파일과 도커 이미지 스크립트를 한 디렉토리에 위치시키고 도커 이미지를 빌드합니다.

docker build -t my-prometheus .

빌드한 이미지를 실행합니다.

docker run -d -p 9090:9090 my-prometheus

http://localhost:9090 에 접속하여 Status -> Targets 항목을 보면 아래와 같이 9323 포트의 호스트 컴퓨터가 조회됩니다.

Graph 메뉴로 이동하여 Execute 버튼 왼쪽의 Metrics Explorer 에서 아래와 같이 메트릭을 선택합니다.

Execute 버튼을 누르면 해당 메트릭의 값이 조회됩니다.

애플리케이션 측정 값 출력하기

앞에서 도커 엔진이 출력하는 측정 값을 연동하였습니다. 이번에는 예제 프로젝트의 애플리케이션에서 프로메테우스 포맷에 맞는 측정 값을 출력하도록 설정해보겠습니다.

먼저 예제 프로젝트는 리액트, 스프링, MySQL을 사용하는 간단한 게시판 프로젝트입니다. 따라서 스프링 서버에서 측정 값을 생성하는 방법에 대해 알아보겠습니다.

스프링 부트가 제공하는 액추에이터 라이브러리는 애플리케이션을 모니터링할 수 있는 기능을 제공합니다.

해당 기능을 추가하기 위해build.gradle 파일에 액추에이터 라이브러리를 추가합니다. 아래와 같이 implementation 'org.springframework.boot:spring-boot-starter-actuator' 부분을 추가합니다.

추가한 이후 백엔드 애플리케이션을 빌드하여 컨테이너를 실행합니다. 도커 환경을 구성하였으므로 docker compose up -d --build 로 애플리케이션을 실행합니다.

http://localhost:{포트}/actuator 에 접속하면 아래와 같은 화면이 출력됩니다. 포트는 docker ps 로 백엔드 컨테이너를 조회하여 호스트 컴퓨터에 연결된 포트를 확인합니다.

기본적으로 액추에이터에서 제공되는 모니터링 기능에 대한 링크가 출력됩니다. 더 많은 모니터링 기능이 보이게 하려면 두 가지 설정을 해야합니다. 엔드포인트를 활성화와 엔드포인트 노출을 설정해야합니다.

자세한 내용은 스프링 부트 공식 문서를 참고합니다.(https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#actuator.endpoints)

기본적으로 엔드포인트 활성화는 shutdown 엔드포인트를 제외하고 모두 활성화 되어있습니다. 따라서 노출만 설정하면 됩니다. shutdown 은 일반적으로 잘 쓰지 않는 것 같습니다. (서버를 원격으로 중지시키기 때문입니다.)

application.yml에서 아래와 같이 엔드포인트 활성화와 노출을 설정할 수 있습니다.

management:
  endpoint:
    shutdown:
      enabled: true # shutdown 엔드포인트 활성화

  endpoints:
    web:
      exposure: # env,beans 를 제외한 모든 엔드포인트 노출
        include: "*"
        exclude: "env,beans"

엔드포인트 활성화는 엔드포인트 별로 설정합니다. application.properties 파일은 아래와 같이 설정합니다.

management.endpoint.{엔드포인트명}.enabled=true

application.yml 파일은 아래와 같이 설정합니다.

management:
  endpoint:
    {엔드포인트명}:
      enabled: true

엔드포인트 노출은 include 와 exclude 를 사용하여 포함시킬 엔드포인트와 제외시킬 엔드포인트를 설정합니다.

설정을 적용하고 다시 실행시킨다음 http://localhost:{포트}/actuator 에 접속하면 아래와 같이 적용된 것을 확인할 수 있습니다.

지금까지 스프링 애플리케이션에 액추에이터를 연동하였습니다. 더 나아가서 프로메테우스에 전달할 측정 값을 출력해보겠습니다.

먼저 스프링은 마이크로미터 라이브리러리를 통해 프로메테우스 같은 모니터링 도구과 연동합니다.

마이크로미터는 애플리케이션 매트릭 파사드(application metrics facade)라고 불리우는데 표준 측정 방식을 제공하여 추상화를 제공합니다. 다양한 모니터링 도구는 마이크로미터 구현체를 제공하여 마이크로미터와 연동합니다. 스프링 애플리케이션은 다양한 모니터링 도구 구현체에 직접 의존하지 않고 마이크로미터 추상화에 의존하도록 설계된 것 같습니다. 스프링부트 액추에이터에 기본으로 마이크로미터가 내장되어 있습니다.

자세한 내용은 아래 문서들을 참고합니다.

https://spring.io/blog/2018/03/16/micrometer-spring-boot-2-s-new-application-metrics-collector#what-is-it

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#actuator.metrics

먼저 스프링에서 기본으로 제공하는 측정 값(메트릭)을 확인해보겠습니다.

http://localhost:{포트}/actuator/metrics 에 접속합니다. 아래와 같이 많은 메트릭들이 기본으로 지원됩니다.

각각의 메트릭은 http://localhost:{포트}/actuator/metrics/{name} 으로 확인가능합니다.

예를 들어 JVM 메모리 사용량은 http://localhost:{포트}/actuator/metrics/jvm.memory.used 로 확인 가능합니다.

스프링 공식 문서에서 제공되는 메트릭들을 확인 가능합니다.

https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#actuator.metrics.supported

프로메테우스 컨테이너에 애플리케이션 연동

위에서 살펴봤던 스프링 부트 액츄에이터와 마이크로미터를 사용하면 수 많은 메트릭들을 자동으로 생성합니다. 프로메테우스는 이런 메트릭들을 주기적으로 수집하고 내부 DB에 저장합니다. 그라파나라는 또 다른 도구를 사용해 프로메테우스에 저장된 데이터를 대시보드로 시각화합니다.

이번에는 프로메테우스에 스프링 부트 애플리케이션을 연동하여 보겠습니다. 먼저 두 가지를 설정해야합니다.

첫 번째로 애플리케이션에서 프로메테우스 포맷에 맞게 메트릭을 만들도록 설정해야합니다. 두 번째로 프로메테우스에서 애플리케이션의 메트릭을 주기적으로 수집하도록 설정해야합니다.

먼저 스프링 부트 애플리케이션의 build.gradle 파일에 프로메테우스 마이크로미터 구현체를 추가합니다. 아래와 같이 implementation 'io.micrometer:micrometer-registry-prometheus' 부분을 추가합니다.

docker compose up -d --build backend 명령어를 통해 백엔드 애플리케이션을 다시 빌드하여 시작합니다.

http://localhost:{포트}/actuator/prometheus 엔드포인트가 추가됩니다. 맨 처음 살펴봤던 도커 엔진에서 출력된 상태 값과 비슷한 포맷의 텍스트가 출력됩니다. 프로메테우스 포맷으로 스프링 부트 액추에이터의 메트릭들이 출력된 것 입니다.

다음으로 프로메테우스에서 애플리케이션의 actuator/prometheus 엔드포인트를 주기적으로 호출하여 메트릭을 수집하도록 설정합니다. 맨 처음 만들었던 prometheus.yml 파일에 아래 내용을 추가합니다. backend:8080 은 docker-compose.yml 에 정의된 백엔드 이미지의 서비스 이름과 포트입니다.

  - job_name: "spring-actuator"
    metrics_path: "/actuator/prometheus"
    scrape_interval: 1s
    static_configs:
      - targets: ["backend:8080"]

프로메테우스 컨테이너가 애플리케이션 컨테이너와 동일한 도커 네트워크를 사용하기 위해 docker-compose.yml 에 프로메테우스 서비스를 추가합니다.

  prometheus:
    build:
      context: ./prometheus
    image: my-prometheus:1.0.0
    ports:
      - "9090:9090"
    networks:
      - app-net

docker rm 명령어로 기존 프로메테우스 컨테이너를 삭제하고
docker compose up -d --build prometheus 명령어로 프로메테우스를 다시 실행시킵니다.

http://localhost:9090 에 접속하여 Status -> Targets 항목을 보면 아래와 같이 백엔드 어플리케이션이 연동된 것을 확인할 수 있습니다.

아래와 같이 Graph 에서 http_server_requests_seconds_count 값을 입력하고 Execute 를 클릭하면 백엔드 메트릭을 조회합니다. 각 행의 가장 우측 열이 해당 메트릭의 값 입니다.

프로메테우스 컨테이너와 그라파나 컨테이너 연동

지금까지 프로메테우스를 사용해 애플리케이션의 메트릭을 수집하고 프로메테우스 DB에 저장하였습니다. 프로메테우스에 저장된 데이터를 대시보드로 구성하기 위해 그라파나라는 도구를 사용합니다.

먼저 그라파나 컨테이너를 시작하기위해 docker-compose.yml 파일에 그라파나 서비스를 정의합니다.

  grafana:
    image: grafana/grafana:10.0.3
    ports:
      - "3000:3000"
    depends_on:
      - prometheus
    networks:
      - app-net

docker compose up -d grafana 명령어로 그라파나 컨테이너를 실행합니다. http://localhost:3000 로 접속하면 로그인 화면이 뜹니다. 초기 사용자명은 admin, 암호 admin 을 입력하여 로그인합니다.

화면 왼쪽의 설정 메뉴에서 Administration -> Data sources -> Add data source 로 이동합니다.

아래 화면처럼 연동할 수 있는 여러가지 데이터 소스가 뜹니다. 프로메테우스를 선택합니다.

여기서 중요한데요. 프로메테우스 서버 URL 입력 칸에 http://localhost:9090 이 아닌 http://prometheus:9090 을 입력합니다. 컨테이너끼리 통신할 때 docker-compose.yml 에서 정의한 서비스 이름이 도메인 이름이 되기 때문입니다.

Save & test 버튼을 클릭했을 때 아래와 같이 프로메테우스 API 연동에 성공했다고 뜨면 설정이 완료됩니다.

대시보드를 추가해보겠습니다. 아래와 같이 설정 메뉴에서 대시보드를 선택합니다.

New -> Import 를 선택합니다.

Import 는 이미 만들어진 대시보드를 불러오는 기능입니다. https://grafana.com/grafana/dashboards 에서 여러 공개된 대시보드를 찾을 수 있습니다. 아래와 같이 spring 이라고 검색하면 나오는 JVM과 Spring Boot 2.1 System Monitor 대시보드를 연동해보겠습니다.

Spring Boot 2.1 System Monitor 대시보드부터 연동해보겠습니다. ID 부분의 숫자를 복사합니다.

그라파나 Import 창에 붙여넣고 Load 를 선택합니다.

아래와 같이 대시보드가 연동되고 프로메테우스를 선택한 뒤 Import 를 선택합니다.

아래와 같이 대시보드가 생성됩니다.

위와 동일한 방법으로 JVM (Micrometer) 대시보드도 연동합니다.

아래와 같이 각각의 항목의 수정 화면에서 어떤 쿼리로 데이터를 불러오는지 확인할 수 있습니다.

완성된 코드는 https://github.com/nefertirii/docker-example/tree/f48f0c01d3ca52cec24b6666d818b37072b37cb2 에 있습니다.

4개의 댓글

comment-user-thumbnail
2023년 8월 4일

좋은 글 감사합니다.

1개의 답글
comment-user-thumbnail
2023년 9월 11일

안녕하세요. 문의사항이 있어 댓글 남깁니다.
컨테이너 환경에 대해 무지하여 아래 내용이 좀 이해가 안가서요..
아래 from/ copy 가 *.sh 형태처럼 수행 되는 문구 인건지 문의 드립니다.
그냥 단순히 from/copy를 나타내신거면 죄송합니다..ㅋㅋ;

@@@@@@@
FROM prom/prometheus:v2.46.0
COPY prometheus.yml /etc/prometheus/prometheus.yml

1개의 답글