본문 바로가기
Projects/청하-청년을 위한 커뮤니티 서비스

[청하] 38. Docker 환경에서 Spring Boot 모니터링 시스템 구축 (with. Prometheus, Grafana)

by Lpromotion 2024. 10. 27.

REF

https://velog.io/@su_under/Docker와-Prometheus-Grafana-연동하기

https://tweety1121.tistory.com/entry/docker에-prometheus-grafana-올리기-Spring-boot

https://velog.io/@roycewon/Spring-boot-모니터링Prometheus-Grafana-docker

 

이전 글에서는 로컬 환경에서 Prometheus와 Grafana를 설치하여 Spring Boot 애플리케이션 모니터링 시스템을 구축했다.

이번에는 Docker와 Docker Compose를 활용하여 운영 서버에 모니터링 시스템을 구축해보았다. 도커를 활용하면 컨테이너 기반으로 Prometheus와 Grafana를 쉽게 관리할 수 있고, 데이터의 영구 저장과 컨테이너의 자동 재시작 등 운영에 필요한 설정도 간편하게 할 수 있다.

 

1. Spring Boot와 Prometheus의 연동 확인

이전 글처럼 스프링부트 프로젝트에 build.gradle 과 application.yml 파일을 변경하고,
https://cheongha.site/actuator/prometheus로 접속하면

prometheus가 연동된 것을 확인할 수 있다.

 

2. docker-compse 설치

docker-compose를 통해 prometheus와 garafana를 세팅하기 위해 우선 docker-compose를 설치했다.

 

2.1. docker-compose 설치하기

sudo curl -L "https://github.com/docker/compose/releases/download/v2.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

최신 버전을 다운로드하고 싶을 경우에 아래 GitHub에서 버전 확인 후 다운로드 하면 된다.

 

Releases · docker/compose

Define and run multi-container applications with Docker - docker/compose

github.com

 

2.2. 파일에 실행 권한 부여

다운로드가 완료되면 실행 권한을 부여한다.

sudo chmod +x /usr/local/bin/docker-compose

 

2.3. 버전 확인

이제 Docker Compose가 제대로 설치되었는지 확인한다.

docker-compose --version

이 명령어를 실행했을 때 Docker Compose의 버전이 출력되면, 성공적으로 설치된 것이다.

 

3. Prometheus 설정

3.1. docker-comspoe 설정 파일 생성

docker-compose-monitoring.yml 파일 생성 (루트 경로에 생성함)

version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml # 설정 파일 마운트
      - ./etc/prometheus/data:/prometheus # 데이터 저장소 마운트
    restart: always
    networks:
      - net

networks:
  net:
    external: true
  • 최신 Prometheus 이미지를 사용하며, 9090 포트를 호스트와 매핑한다.
  • Prometheus 설정 파일(prometheus.yml)과 데이터 디렉터리를 호스트의 디렉터리와 매핑하여 데이터가 영구적으로 저장되도록 한다.
  • restart: always 옵션으로 인해 컨테이너가 종료되더라도 자동으로 다시 시작된다.
  • net 네트워크에 연결되어 있어, 네트워크 내부에서 다른 서비스와 통신할 수 있다.

 

3.2. prometheus 설정 파일 생성

prometheus.yml 은 임의로 작성하고 볼륨으로 넣어줘야 하기 때문에
호스트에 /etc/prometheus/ 경로를 생성하고 prometheus.yml 파일을 생성한다.

sudo mkdir -p /etc/prometheus
sudo vi /etc/prometheus/prometheus.yml

 

prometheus.yml

# my global config
global:
  scrape_interval: 1m # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 1m # 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']

  # Spring Boot Actuator endpoint configuration
  - job_name: "spring-actuator"
    metrics_path: '/actuator/prometheus'
    scrape_interval: 1m  # Spring Actuator에서 메트릭을 1분마다 수집
    static_configs:
      - targets: ['cheongha.site']

각 옵션에 대해서는 이전 글에서 확인할 수 있다.

 

3.3. Prometheus 데이터 저장 경로 생성

데이터 저장 경로를 설정하지 않으면 컨테이너가 재시작될 경우 이전의 데이터가 사라지기 때문에
호스트에 저장되도록 데이터 저장 경로를 생성한다.

sudo mkdir -p /etc/prometheus/data

 

3.4. GCP 방화벽 규칙 추가

prometheus의 웹 인터페이스에 접속하기 위한 9090 포트를 방화벽 규칙에 추가했다.

GCP > VPC 네트워크 > 방화벽 > 방화벽 규칙 만들기

 

3.5. Docker Compose 실행

먼저, docker-compose-monitoring.yml 파일을 사용하여 Prometheus 컨테이너를 실행한다. (루트 디렉토리에서 실행)

sudo docker-compose -f docker-compose-monitoring.yml -p monitoring up -d
  • d 옵션은 컨테이너를 백그라운드에서 실행하도록 한다.

 

실행 중인 컨테이너 확인

Prometheus 컨테이너가 정상적으로 실행 중인지 확인한다.

sudo docker ps

이 명령을 실행하면 현재 실행 중인 Docker 컨테이너 목록이 표시된다.

prometheus라는 이름의 컨테이너가 9090 포트에서 실행 중인지 확인합니다.

 

다운 명령어

sudo docker-compose -f docker-compose-monitoring.yml -p monitoring down

 

3.6. Prometheus 웹 인터페이스 접근

Prometheus가 정상적으로 실행 중이라면, 웹 브라우저를 사용하여 Prometheus 웹 인터페이스에 접근할 수 있다.

http://<서버IP주소 or 도메인이름>:9090

여기에서 Prometheus의 상태를 확인하고, 설정이 올바르게 작동하는지 확인할 수 있다.

접속 성공

 

3.7. Prometheus Targets 확인

Prometheus 웹 인터페이스에서 메트릭이 올바르게 수집되고 있는지 확인하면 된다.

Status > Targets 로 이동하면
prometheus.yml에서 설정한 prometheusspring-actuator 타겟의 상태를 확인할 수있다.

  • prometheus 타겟은 Prometheus 자체의 메트릭을 수집한다.
  • spring-actuator 타겟은 Spring Boot 애플리케이션의 메트릭을 수집한다.

 

4. Grafana 설정

다음은 grafana를 docker-compose 설정 파일에 세팅하고 접속해볼 것이다.

 

4.1. docker-compose 설정 파일 세팅

Prometheus 를 세팅하며 생성했던 docker-compose-monitoring.yml에 grafana 관련 설정도 추가한다.

docker-compose-monitoring.yml

version: '3.8'

services:
  prometheus:
    ...

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - ./etc/grafana/data:/var/lib/grafana
    depends_on:
      - prometheus
    restart: always
    networks:
      - net

networks:
  net:
    external: true
  • 최신 Grafana 이미지를 사용하며, 3000 포트를 호스트와 매핑한다.
  • Grafana의 데이터 디렉터리를 호스트의 디렉터리와 매핑하여 설정과 데이터를 저장한다.
  • prometheus 서비스가 시작된 후에 시작되도록 depends_on 옵션을 설정한다.
  • restart: always 옵션으로 인해 컨테이너가 종료되더라도 자동으로 다시 시작된다.
  • net 네트워크에 연결되어 있어 Prometheus와 통신할 수 있다.

 

4.2. Grafana 데이터 저장 경로 생성

sudo mkdir -p /etc/grafana/data

 

4.3. GCP 방화벽 규칙 추가

grafana 의 웹 인터페이스에 접속하기 위한 3030 포트를 방화벽 규칙에 추가했다.

GCP > VPC 네트워크 > 방화벽 > 방화벽 규칙 만들기

 

4.4. Docker Compose 재실행

다운 명령어

sudo docker-compose -f docker-compose-monitoring.yml -p monitoring down

 

실행 명령어

sudo docker-compose -f docker-compose-monitoring.yml -p monitoring up -d

 

실행 중인 컨테이너 확인

Prometheus 와 Grafana 컨테이너가 정상적으로 실행 중인지 확인한다.

sudo docker ps

Prometheus와 Grafana 컨테이너가 잘 작동되었다.

 

4.5. Grafana 웹 인터페이스 접속

Grafana가 정상적으로 실행 중이라면, 웹 브라우저를 사용하여 Prometheus 웹 인터페이스에 접근할 수 있다.

http://<서버IP주소 or 도메인이름>:3000

 

접속 성공 (초기 계정: admin / admin)

4.6. 데이터 소스 추가

로그인 후 Connections > Add new connection 으로 들어간다.

Prometheus를 데이터 소스로 추가한다.

 

“Promethues server URL” 에 “http://prometheus:9090”을 입력하고, “Save&test” 를 눌러 저장한다.

 

4.7. 대시보드 생성

대시보드는 기존에 있는 템플릿을 이용해서 만들 것이다.

Dashboards > New > Import 선택한다.

https://grafana.com/grafana/dashboards/4701-jvm-micrometer/ 이 템플릿의 URL이나 ID를 복사해서 입력해준다.

 

이름을 설정하고, 데이터 소스를 “prometheus”로 설정한다.

 

https://grafana.com/grafana/dashboards/19004-spring-boot-statistics/

(reivision 버전 사용)

 

4.8. Grafana 시계열 데이터 조회 문제 해결

Request Count 에서 “No data”라고 나와서 쿼리를 변경했다.

기존 쿼리

irate(http_server_requests_seconds_count{instance="$instance", application="$application", uri!~".*(prometheus|health).*", namespace="$Namespace"}[$__rate_interval])

 

수정한 쿼리

irate(http_server_requests_seconds_count{instance="$instance", application="$application", uri!~".*(prometheus|health).*", namespace="$Namespace"}[5m])

[$__rate_interval] 이 부분을 5m으로 바꿨더니 데이터가 나왔다.

원인은 정확하게 모르겠지만 아마 Prometheus 에서 수집된 데이터의 밀도 또는 수집 주기와 관련이 있을 것이다.

다음과 같은 이유들이 있다:

  • 데이터 밀도 문제
    • Prometheus는 데이터를 일정한 간격으로 수집한다. 이 간격이 비교적 길거나, 수집된 데이터가 불규칙하게 존재할 경우, irate() 함수가 정상적으로 계산되지 않을 수 있다.
    • irate()는 가장 최근의 두 데이터 포인트 사이의 변화율을 계산한다. 수집 간격이 너무 넓거나 불규칙하다면, 계산을 위한 충분한 데이터가 없을 수 있다.
  • 수집 주기와 시간 범위 불일치
    • [$__rate_interval]은 Grafana의 템플릿 변수로, 일반적으로 대시보드 설정에 따라 다르지만, 기본적으로는 최근 몇 초, 몇 분 또는 몇 시간의 데이터를 의미한다.
    • 이 간격이 Prometheus의 데이터 수집 주기보다 짧다면, 해당 시간 범위 안에 충분한 데이터가 없을 수 있다.
    • 예를 들어, Prometheus가 1분에 한 번 데이터를 수집하는데 [$__rate_interval]이 15초로 설정되어 있다면, 이 시간 범위 내에 데이터가 없을 가능성이 크다.
  • 변경된 간격(5m)이 더 넓은 범위를 포함
    • [5m]로 변경하면서, 최근 5분 동안의 데이터를 기반으로 변화율을 계산하게 된다. 이로 인해 더 많은 데이터 포인트가 포함되어 계산이 가능해졌을 것이다.
    • 더 넓은 시간 범위를 사용하면, 데이터가 더 많아져서 irate() 함수가 제대로 동작할 확률이 높아진다.

 

[$__rate_interval]은 Grafana에서 자동으로 설정되는 변수이기 때문에, 현재 데이터가 많지 않아서 데이터를 구할 수 없던 것이 아닐까 예상해본다.

 

Response Time 도 “No data”라고 나와서 쿼리를 수정했다.

기존 쿼리

irate(http_server_requests_seconds_sum{instance="$instance", application="$application", exception="none", uri!~".*(prometheus|health).*", namespace="$Namespace"}[$__rate_interval]) / irate(http_server_requests_seconds_count{instance="$instance", application="$application", exception="none",uri!~".*(prometheus|health).*", namespace="$Namespace"}[$__rate_interval])

 

수정 쿼리

irate(http_server_requests_seconds_sum{instance="$instance", application="$application", exception="none", uri!~".*(prometheus|health).*", namespace="$Namespace"}[5m]) / irate(http_server_requests_seconds_count{instance="$instance", application="$application", exception="none",uri!~".*(prometheus|health).*", namespace="$Namespace"}[5m])

 

그 외에도 “GC Count”, “GC Stop the World Duration” 등 “No data”라고 나오는 쿼리는
[$__rate_interval]5m으로 모두 변경해줬다.

 

반응형

댓글