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

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

이 글의 핵심

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

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

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

실무 문제 시나리오

시나리오 1: 서버가 다운돼도 모르겠어요
장애를 사용자가 먼저 알립니다. Prometheus 알림으로 즉시 감지합니다.

시나리오 2: CPU, 메모리 사용량을 모르겠어요
로그로만 확인합니다. Grafana 대시보드로 실시간 확인합니다.

시나리오 3: 병목 지점을 찾기 어려워요
추측으로 최적화합니다. 메트릭으로 정확히 파악합니다.


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: '[email protected]'
        from: '[email protected]'
        smarthost: 'smtp.gmail.com:587'
        auth_username: '[email protected]'
        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:

정리 및 체크리스트

핵심 요약

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

프로덕션 체크리스트

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

같이 보면 좋은 글

  • Kubernetes 실전 가이드
  • Elasticsearch 실전 가이드
  • Redis 고급 가이드

이 글에서 다루는 키워드

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 등 많은 기업에서 사용합니다.

... 996 lines not shown ... Token usage: 63706/1000000; 936294 remaining Start-Sleep -Seconds 3