운영 환경에서 서비스 상태를 파악하려면 메트릭 수집과 시각화가 필수다. Prometheus가 Pull 방식으로 메트릭을 수집하고, Grafana가 그 데이터를 대시보드로 보여주는 조합은 사실상 표준이 됐다. Docker Compose 하나로 이 스택 전체를 로컬에서 재현하거나 프로덕션에 배포할 수 있다.
┌─────────────────────────────────────────────┐
│ docker-compose.yml │
│ │
│ ┌──────────┐ scrape ┌────────────┐ │
│ │ App │◄────────────│ Prometheus │ │
│ │ :8080 │ /metrics │ :9090 │ │
│ └──────────┘ └─────┬──────┘ │
│ │ query │
│ ┌──────▼──────┐ │
│ │ Grafana │ │
│ │ :3000 │ │
│ └─────────────┘ │
└─────────────────────────────────────────────┘
서비스 세 개(앱, Prometheus, Grafana)를 같은 네트워크에 묶는다.
# docker-compose.yml
services:
app:
build: .
ports:
- "8080:8080"
networks:
- monitoring
prometheus:
image: prom/prometheus:v2.51.0
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
ports:
- "9090:9090"
networks:
- monitoring
grafana:
image: grafana/grafana:10.4.0
environment:
- GF_SECURITY_ADMIN_PASSWORD=secret
volumes:
- ./grafana/provisioning:/etc/grafana/provisioning:ro
- grafana_data:/var/lib/grafana
ports:
- "3000:3000"
networks:
- monitoring
networks:
monitoring:
volumes:
grafana_data:
Named volume grafana_data: 컨테이너를 재시작해도 대시보드와 설정이 유지된다. :ro 마운트는 컨테이너가 설정 파일을 변경하지 못하도록 읽기 전용으로 제한한다.
Prometheus가 어느 엔드포인트를 얼마나 자주 수집할지 scrape_configs로 정의한다.
# prometheus/prometheus.yml
global:
scrape_interval: 15s
scrape_configs:
- job_name: "app"
static_configs:
- targets: ["app:8080"]
metrics_path: /metrics
컨테이너 이름 app이 DNS로 해석되므로 IP 대신 서비스 이름을 그대로 쓴다.
Grafana를 띄울 때마다 수동으로 datasource를 추가하는 번거로움을 없애려면 프로비저닝 디렉터리를 마운트한다.
# grafana/provisioning/datasources/prometheus.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://prometheus:9090
isDefault: true
# grafana/provisioning/dashboards/default.yml
apiVersion: 1
providers:
- name: default
type: file
options:
path: /etc/grafana/provisioning/dashboards
프로비저닝(Provisioning): Grafana가 시작할 때 YAML 파일을 읽어 datasource와 대시보드를 자동으로 등록하는 기능. UI 없이 코드로 Grafana 상태를 관리할 수 있다.
Node.js 앱이라면 prom-client 라이브러리 하나로 /metrics 엔드포인트를 추가할 수 있다.
import { collectDefaultMetrics, Registry } from "prom-client";
import express from "express";
const register = new Registry();
collectDefaultMetrics({ register });
const app = express();
app.get("/metrics", async (_req, res) => {
res.set("Content-Type", register.contentType);
res.end(await register.metrics());
});
collectDefaultMetrics: 프로세스 CPU, 메모리, 이벤트 루프 지연 등 Node.js 기본 지표를 자동으로 등록해준다.
| 항목 | Prometheus | Grafana |
|---|---|---|
| 포트 | 9090 | 3000 |
| 설정 파일 | prometheus.yml | provisioning YAML |
| 데이터 저장 | 로컬 TSDB | Named Volume |
| 인증 | 기본 없음 | GF_SECURITY_ADMIN_PASSWORD |
docker compose up -d 한 번으로 스택이 뜨고, localhost:3000에서 Grafana 대시보드를 확인할 수 있다. 스케일아웃이 필요하면 prometheus.yml의 targets 배열에 인스턴스를 추가하면 된다.