한줄 소개
https://prometheus.io/docs/introduction/overview/
최초 SoundCloud에서 만들어진, 시스템 모니터링과 경보(Alert) 도구 모음이다
Docker Compose로 Prometheus 실행
https://hub.docker.com/r/prom/prometheus
mkdir data
vi compose.yml
services:
some-prometheus:
container_name: some-prometheus
image: prom/prometheus:v2.52.0
ports:
- 9090:9090
volumes:
- ./data:/prometheus
docker compose up
컨테이너 내부에서 프로메테우스가 사용하는 폴더를 확인해보자
docker exec -it some-prometheus /bin/sh
tree /prometheus
/prometheus
├── chunks_head
├── lock
├── queries.active
└── wal
└── 00000000
2 directories, 3 files
tree /usr/share/prometheus
/usr/share/prometheus
├── console_libraries
│ ├── menu.lib
│ └── prom.lib
└── consoles
├── index.html.example
├── node-cpu.html
├── node-disk.html
├── node-overview.html
├── node.html
├── prometheus-overview.html
└── prometheus.html
2 directories, 9 files
tree /etc/prometheus
/etc/prometheus
├── console_libraries -> /usr/share/prometheus/console_libraries
├── consoles -> /usr/share/prometheus/consoles/
└── prometheus.yml
0 directories, 3 files
cat /etc/prometheus/prometheus.yml
# 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"]
Prometheus 둘러보기
웹 브라우저에서 http://localhost:9090로 진입한다
메뉴 > Status > Command-Line Flags
프로메테우스 실행 시의 옵션 노출
메뉴 > Status > Configuration
prometheus.yml 설정값을 볼 수 있다
메뉴 > Status > Targets
prometheus (1/1 up)이라는 항목이 보일 것이다. show more 버튼을 클릭해보자. 표 하나가 보여진다

http://localhost:9090/metrics 라는 종단점(Endpoint)의 상태는 UP이고 키="값" 형태의 레이블들을 가졌고, 수집(Scrape) 시간 정보, 에러 등의 정보를 확인할 수 있다
종단점 링크를 클릭해보면 화면에 보여진 localhost가 아닌 http://c94672ef60b1:9090/metrics 이런 URI로 이동한다. 왜 그런지는 모르겠다. 맥에서 Rancher Desktop으로 도커를 사용할 때의 이슈인 거 같다. 혹시 몰라 네트워크 모드를 host로 변경해봤는데 이 때는 http://lima-rancher-desktop:9090/metrics로 접속되었다
직접 http://localhost:9090/metrics를 입력해서 진입하면 정상적으로 아래와 같은 내용이 출력된다
# HELP go_gc_duration_seconds A summary of the pause duration of garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 3.6707e-05
go_gc_duration_seconds{quantile="0.25"} 0.000121667
go_gc_duration_seconds{quantile="0.5"} 0.000586749
go_gc_duration_seconds{quantile="0.75"} 0.002301834
go_gc_duration_seconds{quantile="1"} 0.027133833
go_gc_duration_seconds_sum 0.096830956
go_gc_duration_seconds_count 53
..
이 내용은 무엇일까?
프로메테우스는 Target에 해당하는 대상의 HTTP 종단점으로부터 Metric을 주기적으로 Polling(Pulling)하는 방식으로 데이터를 수집한다
프로메테우스 그 자체도 같은 방식으로 데이터를 노출하기 때문에, 자신의 Health를 수집하고 모니터링할 수 있다. 그렇기 때문에 위와 같이 프로메테우스에 대한 수집 정보가 노출되는 것이다
Metric이란 수집되는 시계열 데이터를 의미하며, 시계열(Time series)은 일정 시간 간격으로 배치된 데이터들의 수열을 말한다
호스트 OS에서 prometheus.yml 설정할 수 있게 하기
프로메테우스 설정도 도커 컨테이너 외부에서 관리되도록 해야한다
작업 폴더에서 prometheus.yml 파일을 만들어 도커 볼륨을 통해 컨테이너 내부에 배포되도록 해야한다
vi prometheus.yml
앞에서 출력했던 컨테이너 기본 설정을 복붙한다
보시다시피 수집 설정에서 잡 이름이 prometheus이고 기본 스킴인 http, 기본 메트릭 경로인 /metrics, 기본 포트인 9090을 사용하고 있다
..
# 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"]
vi compose.yml
services:
some-prometheus:
container_name: some-prometheus
image: prom/prometheus:v2.52.0
ports:
- 9090:9090
volumes:
- ./data:/prometheus
- ./prometheus.yml:/etc/prometheus/prometheus.yml
docker compose down
docker compose up
Node Exporter 타겟 추가하기
이제 실용적인 타겟을 추가해보며 프로메테우스를 좀 더 알아보도록 하자
노드 익스포터는 호스트 시스템을 모니터링하기 위해 설계되었다. 이로 인해 프로메테우스가 동작하는 호스트의 하드웨어와 커널 관련 메트릭을 수집할 수 있다
Docker Compose로 노드 익스포터 실행
https://hub.docker.com/r/prom/node-exporter
컨테이너로 실행하면 추가적으로 해야할 작업들이 꽤 있어보여서 추후에 시도해보도록 하겠다
노드 익스포터 설치 후 OS 서비스로 등록
https://prometheus.io/docs/guides/node-exporter/
https://prometheus.io/download/#node_exporter
맥 환경이기 때문에 darwin OS 바이너리를 다운로드한다. (터미널에서 uname을 치면 Darwin이 출력된다)
tar xvfz node_exporter-1.8.1.darwin-amd64.tar.gz
ln -s node_exporter-1.8.1.darwin-amd64 node-exporter
cd node-exporter
./node_exporter
9100번 포트로 노드 익스포터가 실행된다
curl http://localhost:9100/metrics
접두사 node_인 항목들이 시스템 메트릭이다
OS 서비스로 등록하는 것은 추후에 작성하겠다
Prometheus 타겟에 Node Exporter 추가하기
vi prometheus.yml
..
scrape_configs
..
- job_name: node-exporter
static_configs:
- targets: ["localhost:9100"]
docker compose down
docker compose up
Targets 화면에 node-exporter 항목이 노출되는 것을 확인할 수 있는데, 상태가 UP이 되지 않는다. 이유는 컨테이너 안에서 프로메테우스는 localhost로 접근이 가능하나, 노드 익스포터는 컨테이너 밖인 호스트 OS에서 실행되기 때문이다
컨테이너에서 호스트 포트로 접근할 수 있어야 하는데 host.docker.internal이라는 도메인을 사용하면 접근 가능하다
vi prometheus.yml
..
scrape_configs
..
- job_name: node-exporter
static_configs:
- targets: ["host.docker.internal:9100"]
docker compose down
docker compose up
이제 상태가 UP이 되는 것을 확인할 수 있다

Expression browser를 통해 노드 익스포터 메트릭 살펴보기
Graph 메뉴에 진입한다
Expression 입력 폼에 타이핑을 하면 자동완성이 된다. Execute 버튼 왼쪽 버튼을 눌러도 된다
이곳에서 수집된 메트릭에 대해서 입맛대로 질의를 할 수 있다
메모리 사용량을 확인해보자. 단위는 Bytes다
메모리 전체 크기: node_memory_total_bytes
사용 중인 메모리 크기: node_memory_active_bytes
여유 메모리 크기: node_memory_free_bytes
메모리 사용률을 확인해보고 싶다면 아래와 같은 식을 사용하면 된다
node_memory_active_bytes / node_memory_total_bytes * 100
Spring Boot 애플리케이션의 메트릭을 프로메테우스에 맞게 노출
스프링 부트의 Actuator 기능을 사용하면 HTTP 종단점으로부터 메트릭을 수집할 수 있다
https://docs.spring.io/spring-boot/reference/actuator/index.html
액추에이터의 metrics 종단점을 노출시키면 현재 애플리케이션의 메트릭 정보를 볼 수 있다
application.yml
management:
endpoints:
enabled-by-default: false
web:
exposure:
include: "metrics"
endpoint:
metrics.enabled: true
위와 같이 설정하고 애플리케이션을 시작한다
아래 종단점으로 메트릭 목록을 확인할 수 있다
http://localhost:8080/actuator/metrics
{
"names": [
"application.ready.time",
"application.started.time",
"disk.free",
"disk.total",
"executor.active",
"executor.completed",
"executor.pool.core",
"executor.pool.max",
"executor.pool.size",
"executor.queue.remaining",
"executor.queued",
"http.server.requests.active",
"jvm.buffer.count",
"jvm.buffer.memory.used",
"jvm.buffer.total.capacity",
"jvm.classes.loaded",
"jvm.classes.unloaded",
"jvm.compilation.time",
"jvm.gc.live.data.size",
"jvm.gc.max.data.size",
"jvm.gc.memory.allocated",
"jvm.gc.memory.promoted",
"jvm.gc.overhead",
"jvm.info",
"jvm.memory.committed",
"jvm.memory.max",
"jvm.memory.usage.after.gc",
"jvm.memory.used",
"jvm.threads.daemon",
"jvm.threads.live",
"jvm.threads.peak",
"jvm.threads.started",
"jvm.threads.states",
"logback.events",
"process.cpu.time",
"process.cpu.usage",
"process.files.max",
"process.files.open",
"process.start.time",
"process.uptime",
"system.cpu.count",
"system.cpu.usage",
"system.load.average.1m",
"tomcat.sessions.active.current",
"tomcat.sessions.active.max",
"tomcat.sessions.alive.max",
"tomcat.sessions.created",
"tomcat.sessions.expired",
"tomcat.sessions.rejected"
]
}
위 메트릭 이름 중 하나를 URI에 추가하면 상세 정보를 확인할 수 있다
http://localhost:8080/actuator/metrics/jvm.memory.used
{
"name": "jvm.memory.used",
"description": "The amount of used memory",
"baseUnit": "bytes",
"measurements": [
{
"statistic": "VALUE",
"value": 85360080
}
],
"availableTags": [
{
"tag": "area",
"values": [
"heap",
"nonheap"
]
},
{
"tag": "id",
"values": [
"G1 Survivor Space",
"Compressed Class Space",
"Metaspace",
"CodeCache",
"G1 Old Gen",
"G1 Eden Space"
]
}
]
}
여기서 문제가 하나 있는데, 이 메트릭들의 형식은 프로메테우스가 처리하는 형식이 아니란 것이다. 결국 프로메테우스가 원하는 형식으로 제공을 해야하는데 생각만해도 귀찮다
이럴 때 Micrometer를 이용하면 모니터링 도구 변경에 유연해진다. 마이크로미터는 마치 로깅 계의 SLF4J와 같은 Fasade다
- 마이크로미터가 정한 표준 형식으로 메트릭을 전달하고
- 스프링 부트 액추에이터가 제공하는 종단점 중 /actuator/prometheus 사용
- 모니터링 도구에 맞는 구현체를 선택하면 끝이다
- micrometer-registry-prometheus 의존성 사용
위 예제를 위해 프로젝트 하나를 만들어 두었다
https://github.com/venzersiz/learn-spring-boot-actuator
프로메테우스에서 스프링 부트 애플리케이션의 메트릭 수집
vi prometheus.yml
..
- job_name: spring-boot-application
static_configs:
- targets: ["host.docker.internal:8080"]
metrics_path: /actuator/prometheus
기존 설정에는 없던 metrics_path 설정이 있는데, 기본적으로 metrics_path는 /metrics로 되어 있어 수집되지 않기 때문이다
docker compose down
docker compose up
Targets 화면으로 가면 정상적으로 노출이 된다

Graph 화면에서 JVM의 Metaspace 크기를 확인해보자
jvm_memory_used_bytes
jvm_memory_used_bytes{id="Metaspace"}