Kubernetes 클러스터를 운영하면서 모니터링 없이 버티는 것은 계기판 없이 비행기를 조종하는 것과 같습니다. Prometheus는 메트릭 수집·저장·쿼리를, Grafana는 시각화·알림을 담당하며, 이 조합은 Kubernetes 모니터링의 사실상 표준입니다.
이 글에서는 Prometheus의 Pull 기반 아키텍처를 이해하고, kube-prometheus-stack으로 한 번에 설치하며, PromQL 실전 쿼리로 핵심 지표를 추출하고, Grafana 대시보드 설계와 Alertmanager 알림 라우팅까지 운영 수준으로 정리합니다.
1. Prometheus 아키텍처: Pull 모델의 장점
대부분의 모니터링 시스템이 에이전트가 데이터를 중앙 서버로 보내는 Push 방식인 반면, Prometheus는 타겟의 /metrics 엔드포인트를 주기적으로 긁어오는(scrape) Pull 방식을 씁니다.
| 비교 항목 | Push 모델 | Pull 모델 (Prometheus) |
|---|---|---|
| 타겟 장애 감지 | 데이터가 안 오면 추정 | scrape 실패로 즉시 감지 (up == 0) |
| 서비스 디스커버리 | 에이전트가 서버 주소를 알아야 함 | K8s API로 Pod/Service 자동 발견 |
| 로컬 디버깅 | 서버 없으면 확인 불가 | curl localhost:8080/metrics로 즉시 확인 |
| 부하 제어 | 에이전트 수에 비례해 서버 부하 증가 | scrape interval로 Prometheus가 부하 제어 |
2. kube-prometheus-stack 설치: 한 번에 끝내기
Prometheus, Grafana, Alertmanager, node-exporter, kube-state-metrics를 개별 설치하면 설정이 복잡합니다. kube-prometheus-stack Helm 차트는 이 모든 것을 하나로 묶어 제공합니다.
# 네임스페이스 + Helm 설치
helm repo add prometheus-community
https://prometheus-community.github.io/helm-charts
helm repo update
helm install monitoring prometheus-community/kube-prometheus-stack
--namespace monitoring --create-namespace
-f values-monitoring.yaml
# values-monitoring.yaml 핵심 설정
prometheus:
prometheusSpec:
retention: 15d
storageSpec:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
grafana:
adminPassword: "변경필수"
persistence:
enabled: true
size: 10Gi
alertmanager:
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
resources:
requests:
storage: 5Gi
설치 후 포함되는 컴포넌트:
- Prometheus Operator: ServiceMonitor·PodMonitor CRD로 scrape 대상을 선언적 관리
- node-exporter: 노드별 CPU, 메모리, 디스크, 네트워크 메트릭
- kube-state-metrics: Pod, Deployment, StatefulSet 등 K8s 오브젝트 상태 메트릭
- Grafana: 사전 구성된 대시보드 20개 이상 포함
3. ServiceMonitor: 앱 메트릭 자동 수집
애플리케이션이 /metrics 엔드포인트를 노출하면, ServiceMonitor를 생성하는 것만으로 Prometheus가 자동으로 scrape합니다.
# 앱 Service
apiVersion: v1
kind: Service
metadata:
name: my-app
labels:
app: my-app
spec:
ports:
- name: http
port: 3000
- name: metrics
port: 9090
selector:
app: my-app
---
# ServiceMonitor
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
labels:
release: monitoring # kube-prometheus-stack 릴리스 이름과 일치
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics
interval: 15s
path: /metrics
주의: ServiceMonitor의 labels에 release: monitoring을 반드시 추가해야 합니다. Prometheus Operator는 이 레이블로 어떤 ServiceMonitor를 수집할지 필터링합니다. 이 레이블이 없으면 메트릭이 수집되지 않는데, 가장 흔한 트러블슈팅 포인트입니다.
4. PromQL 실전 쿼리: 핵심 지표 5가지
PromQL은 Prometheus의 쿼리 언어입니다. 운영에서 반드시 모니터링해야 할 핵심 쿼리 다섯 가지를 정리합니다.
| 지표 | PromQL | 의미 |
|---|---|---|
| CPU 사용률 | rate(container_cpu_usage_seconds_total{namespace="my-app"}[5m]) |
최근 5분간 초당 CPU 사용량 |
| 메모리 사용률 | container_memory_working_set_bytes{namespace="my-app"} / container_spec_memory_limit_bytes * 100 |
Limit 대비 실제 사용 비율 |
| HTTP 에러율 | sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) * 100 |
5xx 비율 (SLO 기준) |
| 응답 지연 P99 | histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])) |
99번째 백분위 응답 시간 |
| Pod 재시작 횟수 | increase(kube_pod_container_status_restarts_total[1h]) > 0 |
최근 1시간 내 재시작된 컨테이너 |
rate()는 counter 타입 메트릭의 초당 증가율을 계산합니다. counter는 항상 증가하는 값(요청 수, 에러 수)이므로, 원시 값보다 rate()로 변환해야 의미 있는 그래프가 됩니다.
5. Grafana 대시보드 설계 원칙
kube-prometheus-stack은 20개 이상의 대시보드를 기본 제공하지만, 앱 전용 대시보드는 직접 만들어야 합니다. RED 메서드(Rate, Errors, Duration)를 기준으로 설계하면 핵심 지표를 놓치지 않습니다.
# ConfigMap으로 Grafana 대시보드 프로비저닝
apiVersion: v1
kind: ConfigMap
metadata:
name: my-app-dashboard
namespace: monitoring
labels:
grafana_dashboard: "1" # Grafana sidecar가 자동 로드
data:
my-app.json: |
{
"dashboard": {
"title": "My App - RED Metrics",
"panels": [
{
"title": "Request Rate",
"type": "timeseries",
"targets": [{
"expr": "sum(rate(http_requests_total{app="my-app"}[5m]))"
}]
},
{
"title": "Error Rate (%)",
"type": "stat",
"targets": [{
"expr": "sum(rate(http_requests_total{app="my-app",status=~"5.."}[5m])) / sum(rate(http_requests_total{app="my-app"}[5m])) * 100"
}]
},
{
"title": "P99 Latency",
"type": "timeseries",
"targets": [{
"expr": "histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{app="my-app"}[5m])) by (le))"
}]
}
]
}
}
grafana_dashboard: "1" 레이블을 가진 ConfigMap은 Grafana sidecar가 자동으로 감지하고 대시보드로 로드합니다. JSON 파일을 수동으로 업로드할 필요가 없습니다.
6. Alertmanager 알림 라우팅 설정
PrometheusRule로 알림 조건을 정의하고, Alertmanager가 Slack, PagerDuty, 이메일 등으로 라우팅합니다.
# PrometheusRule: 알림 조건 정의
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: my-app-alerts
labels:
release: monitoring
spec:
groups:
- name: my-app
rules:
- alert: HighErrorRate
expr: |
sum(rate(http_requests_total{app="my-app",status=~"5.."}[5m]))
/ sum(rate(http_requests_total{app="my-app"}[5m])) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "5xx 에러율 5% 초과"
description: "{{ $labels.namespace }}/{{ $labels.pod }}: 에러율 {{ $value | humanizePercentage }}"
- alert: PodCrashLooping
expr: increase(kube_pod_container_status_restarts_total[1h]) > 3
for: 10m
labels:
severity: warning
annotations:
summary: "Pod 반복 재시작 감지"
# Alertmanager 라우팅 (values-monitoring.yaml)
alertmanager:
config:
route:
receiver: "slack-default"
group_by: ["alertname", "namespace"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- receiver: "pagerduty-critical"
match:
severity: critical
receivers:
- name: "slack-default"
slack_configs:
- api_url: "https://hooks.slack.com/services/..."
channel: "#alerts"
title: "{{ .GroupLabels.alertname }}"
text: "{{ range .Alerts }}{{ .Annotations.summary }}n{{ end }}"
- name: "pagerduty-critical"
pagerduty_configs:
- service_key: "your-pagerduty-key"
group_by는 같은 alertname과 namespace의 알림을 묶어 하나의 메시지로 보냅니다. Pod가 100개인 서비스에서 동시에 에러가 나면, 100건이 아니라 1건의 그룹 알림만 전송됩니다.
7. 운영에서 자주 하는 실수 5가지
- retention과 스토리지 미설정 — 기본 retention은 15일이지만 PV 없이 emptyDir를 쓰면 Pod 재시작 시 전체 메트릭이 날아갑니다. 반드시 PersistentVolume을 설정하세요.
- ServiceMonitor 레이블 불일치 —
release: monitoring레이블이 없으면 Prometheus가 ServiceMonitor를 무시합니다. 메트릭이 안 들어올 때 가장 먼저 확인할 포인트입니다. - cardinality 폭발 — 사용자 ID나 요청 URL을 레이블로 넣으면 메트릭 시리즈가 기하급수적으로 증가하고, Prometheus 메모리가 터집니다. 레이블 값은 반드시 유한한 집합이어야 합니다.
- 알림 임계값을 너무 민감하게 설정 — CPU 50% 초과로 알림을 걸면 매일 수십 건의 알림이 오고, 팀이 알림을 무시하게 됩니다. SLO 기반으로 에러율, 지연시간 중심의 알림을 설계하세요.
- Grafana 대시보드를 UI에서만 수정 — Pod 재시작이나 업그레이드 시 사라집니다. ConfigMap이나 Git으로 대시보드를 관리하고, Grafana sidecar로 자동 프로비저닝하세요.
마무리
Prometheus + Grafana는 Kubernetes 모니터링의 사실상 표준이며, kube-prometheus-stack으로 빠르게 구축할 수 있습니다. ServiceMonitor로 앱 메트릭을 자동 수집하고, PromQL로 핵심 지표를 추출하며, Alertmanager로 적절한 채널에 알림을 라우팅하면 운영 가시성을 체계적으로 확보할 수 있습니다.
Kubernetes 운영을 더 깊이 다루고 싶다면, ArgoCD GitOps 실전 가이드와 Kubernetes HPA 심화 가이드도 함께 참고해보세요.
Prometheus 알림 룰 + Grafana 대시보드 템플릿이 필요하신가요?
이 글에서 다룬 RED 메트릭 대시보드 JSON, PrometheusRule YAML, Alertmanager 라우팅 설정을 바로 적용할 수 있는 템플릿 세트를 준비했습니다. 아래 댓글로 “모니터링 템플릿”이라고 남겨주시면 보내드립니다.