본문으로 건너뛰기 Prometheus & Grafana 완벽 가이드 | 모니터링·메트릭·알림·대시보드

Prometheus & Grafana 완벽 가이드 | 모니터링·메트릭·알림·대시보드

Prometheus & Grafana 완벽 가이드 | 모니터링·메트릭·알림·대시보드

이 글의 핵심

Prometheus와 Grafana로 시스템 모니터링을 구축하는 완벽 가이드. 메트릭 수집, PromQL, 알림, 대시보드, 실전 예제까지 완벽 정리. Prometheus·Grafana·Monitoring 중심으로 설명합니다.

이 글의 핵심

Prometheus와 Grafana로 시스템 모니터링을 구축하는 완벽 가이드입니다. 메트릭 수집, PromQL, 알림, 대시보드, 실전 예제까지 완벽 정리했습니다.

실무 경험 공유: 마이크로서비스 모니터링을 Prometheus + Grafana로 구축하면서, 장애 감지 시간을 30분에서 1분으로 단축하고 시스템 가시성을 크게 향상시킨 경험을 공유합니다.

들어가며: “서버 상태를 모르겠어요”

실무에서 마주치는 문제들

서버가 다운돼도 모르겠어요

장애를 사용자가 먼저 알립니다. Prometheus 알림으로 즉시 감지합니다. CPU, 메모리 사용량을 모르겠어요

로그로만 확인합니다. Grafana 대시보드로 실시간 확인합니다. 병목 지점을 찾기 어려워요

추측으로 최적화합니다. 메트릭으로 정확히 파악합니다.

1. Prometheus란?

핵심 특징

Prometheus는 오픈소스 모니터링 시스템입니다. 주요 기능

  • 메트릭 수집: Pull 방식
  • 시계열 DB: 시간 기반 데이터
  • PromQL: 강력한 쿼리 언어
  • 알림: Alertmanager 통합
  • 서비스 디스커버리: 자동 타겟 발견

2. 설치

Docker Compose

# docker-compose.yml
version: '3.8'
services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
volumes:
  prometheus-data:
  grafana-data:

3. Prometheus 설정

prometheus.yml

# prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
scrape_configs:
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']
  - job_name: 'my-app'
    static_configs:
      - targets: ['localhost:8000']

4. Node.js 메트릭

설치

npm install prom-client

Express 통합

// server.ts
import express from 'express';
import client from 'prom-client';
const app = express();
// 기본 메트릭 수집
const register = new client.Registry();
client.collectDefaultMetrics({ register });
// 커스텀 메트릭
const httpRequestDuration = new client.Histogram({
  name: 'http_request_duration_seconds',
  help: 'Duration of HTTP requests in seconds',
  labelNames: ['method', 'route', 'status'],
  registers: [register],
});
const httpRequestTotal = new client.Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests',
  labelNames: ['method', 'route', 'status'],
  registers: [register],
});
// Middleware
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const duration = (Date.now() - start) / 1000;
    
    httpRequestDuration.observe(
      { method: req.method, route: req.route?.path || req.path, status: res.statusCode },
      duration
    );
    httpRequestTotal.inc({
      method: req.method,
      route: req.route?.path || req.path,
      status: res.statusCode,
    });
  });
  next();
});
// 메트릭 엔드포인트
app.get('/metrics', async (req, res) => {
  res.set('Content-Type', register.contentType);
  res.end(await register.metrics());
});
app.listen(8000, () => console.log('Server running on :8000'));

5. PromQL

기본 쿼리

# 현재 값
http_requests_total
# 레이블 필터
http_requests_total{method="GET"}
http_requests_total{status="200"}
# 범위 쿼리
http_requests_total[5m]
# Rate (초당 증가율)
rate(http_requests_total[5m])
# Sum
sum(rate(http_requests_total[5m])) by (status)
# Avg
avg(http_request_duration_seconds)

복잡한 쿼리

# 5분간 평균 응답 시간
rate(http_request_duration_seconds_sum[5m]) / rate(http_request_duration_seconds_count[5m])
# 에러율 (5xx)
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))
# CPU 사용률
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

6. Grafana 대시보드

Prometheus 데이터 소스 추가

  1. Grafana 접속: http://localhost:3000 (admin/admin)
  2. Configuration → Data Sources → Add data source
  3. Prometheus 선택
  4. URL: http://prometheus:9090
  5. Save & Test

대시보드 생성

{
  "dashboard": {
    "title": "Application Metrics",
    "panels": [
      {
        "title": "Request Rate",
        "targets": [
          {
            "expr": "rate(http_requests_total[5m])"
          }
        ],
        "type": "graph"
      },
      {
        "title": "Error Rate",
        "targets": [
          {
            "expr": "sum(rate(http_requests_total{status=~\"5..\"}[5m])) / sum(rate(http_requests_total[5m]))"
          }
        ],
        "type": "graph"
      }
    ]
  }
}

7. 알림

Alertmanager 설정

# alertmanager.yml
global:
  resolve_timeout: 5m
route:
  group_by: ['alertname']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 1h
  receiver: 'email'
receivers:
  - name: 'email'
    email_configs:
      - to: 'ops@example.com'
        from: 'alertmanager@example.com'
        smarthost: 'smtp.gmail.com:587'
        auth_username: 'alertmanager@example.com'
        auth_password: 'password'

Alert Rules

# alerts.yml
groups:
  - name: example
    rules:
      - alert: HighErrorRate
        expr: sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) > 0.05
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "High error rate detected"
          description: "Error rate is {{ $value | humanizePercentage }}"
      - alert: HighCPUUsage
        expr: 100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"

8. 실전 예제: 전체 스택

설정 파일 예시입니다.

# docker-compose.yml
version: '3.8'
services:
  # 애플리케이션
  app:
    build: .
    ports:
      - "8000:8000"
  # Node Exporter (시스템 메트릭)
  node-exporter:
    image: prom/node-exporter:latest
    ports:
      - "9100:9100"
  # Prometheus
  prometheus:
    image: prom/prometheus:latest
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./alerts.yml:/etc/prometheus/alerts.yml
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
  # Alertmanager
  alertmanager:
    image: prom/alertmanager:latest
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
  # Grafana
  grafana:
    image: grafana/grafana:latest
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - grafana-data:/var/lib/grafana
volumes:
  grafana-data:

8.1 시계열 저장소(TSDB)와 샘플링

Prometheus는 수집된 샘플을 블록 단위로 로컬 디스크에 쌓으며, 주기적으로 컴팩션합니다. 스크랩 간격(scrape_interval)이 짧을수록 해상도는 좋아지지만 디스크·CPU 부하가 커집니다. 알림 규칙의 for 지속 시간은 “짧은 스파이크 무시”에 쓰이므로, 스크랩 간격·evaluation_interval·for함께 설계해야 합니다.

카티널리티(cardinality) 는 시계열 수를 폭증시키는 주범입니다. user_id, request_id처럼 값의 종류가 무한에 가까운 레이블을 붙이면 메모리가 빠르게 고갈됩니다. 해결책은 레이블 설계 가이드를 팀에 공유하며, 필요 시 집계 레이어(recording rule) 로 상위 차원만 남기는 것입니다.

Recording rule 예시

groups:
  - name: api_recording
    interval: 30s
    rules:
      - record: job:http_requests:rate5m
        expr: sum by (job, status) (rate(http_requests_total[5m]))

대시보드와 알림은 가능하면 레코딩된 시계열을 조회해 PromQL 부하를 줄입니다.


8.2 Grafana·프로덕션 운영

  • 데이터 소스 프로비저닝: 대시보드를 JSON으로 Git에 두고 환경별 변수만 바꿉니다.
  • 알림 채널: Alertmanager가 1차이며, Grafana 알림은 UI 팀과 연동할 때 유용합니다. 이중화 시 같은 사건이 두 번 올 수 있으므로 라우팅을 분리합니다.
  • 보안: Grafana는 관리자 계정·플러그인 공급망을 주기적으로 갱신합니다.

9. 트러블슈팅

증상흔한 원인점검
query timed out카티널리티 과다, 긴 범위 쿼리topk, aggregate, 레코딩 룰
타겟 DOWN네트워크·TLS·스크랩 경로 변경/targets UI, up 메트릭
알림이 안 울림for가 김, 라벨 매칭 실패Alertmanager 라우트 트리
디스크 풀보관 기간·샘플 과다Retention, wal 모니터링, Thanos/Cortex 검토

정리 및 체크리스트

핵심 요약

  • Prometheus: 메트릭 수집 및 저장
  • PromQL: 강력한 쿼리 언어
  • Grafana: 시각화 대시보드
  • Alertmanager: 알림 관리
  • Exporter: 다양한 시스템 메트릭
  • 고가용성: 클러스터 지원

프로덕션 체크리스트

  • Prometheus 설치
  • 메트릭 수집 구현
  • Grafana 대시보드 생성
  • Alert Rules 설정
  • Alertmanager 구성
  • 백업 설정
  • 고가용성 구성

같이 보면 좋은 글


이 글에서 다루는 키워드

Prometheus, Grafana, Monitoring, Metrics, DevOps, Observability, Alert

자주 묻는 질문 (FAQ)

Q. Prometheus vs ELK Stack, 어떤 게 나은가요?

A. Prometheus는 메트릭에 특화되어 있습니다. ELK는 로그에 특화되어 있습니다. 둘 다 사용하는 것을 권장합니다.

Q. 데이터 보관 기간은?

A. 기본 15일입니다. 장기 저장은 Thanos나 Cortex를 사용하세요.

Q. Grafana는 무료인가요?

A. 네, 오픈소스이며 무료입니다. Grafana Cloud는 유료 관리형 서비스입니다.

Q. 프로덕션에서 사용해도 되나요?

A. 네, SoundCloud, DigitalOcean 등 많은 기업에서 사용합니다.