Kubernetes 클러스터를 운영하는데 모니터링이 없다면, 장애가 발생했을 때 "어디서, 왜, 얼마나" 문제인지 알 수 없습니다. kubectl top으로는 현재 순간만 볼 수 있고, 과거 데이터도 없고, 알림도 없습니다. Prometheus + Grafana 스택은 이 문제를 해결하는 오픈소스 표준 조합입니다.
핵심 요약
- Prometheus는 Pull 기반 메트릭 수집기이며, Grafana는 시각화 도구입니다. 이 조합은 Kubernetes 모니터링의 사실상 표준(de facto standard)입니다.
- kube-prometheus-stack Helm 차트를 사용하면 Prometheus, Grafana, Alertmanager, node-exporter, kube-state-metrics를 한 번에 배포할 수 있습니다.
- 메트릭 수집 구조를 이해해야 합니다. Prometheus가 각 타겟의 /metrics 엔드포인트를 주기적으로 스크레이핑합니다.
- 대시보드는 USE(Utilization, Saturation, Errors) 방법론 기반으로 설계하면 장애 원인을 빠르게 좁힐 수 있습니다.
- 알림은 "즉시 행동이 필요한 것"만 설정합니다. 알림 피로(Alert Fatigue)를 줄이는 것이 운영 품질의 핵심입니다.
1. 왜 Prometheus + Grafana인가
EKS에서 마이크로서비스 10개를 운영하고 있다고 가정합니다. 어느 날 사용자가 "응답이 느리다"고 신고합니다.
이때 확인해야 할 것들:
- 어떤 Pod의 CPU/메모리가 한계에 도달했는가?
- 특정 노드에 Pod가 몰려 있는가?
- 최근 30분간 에러율이 증가했는가?
- 어떤 Deployment의 레플리카가 줄어들었는가?
kubectl로 하나씩 확인하면 10분이 걸립니다. 대시보드가 있으면 30초 만에 파악할 수 있습니다.
도구 선택 이유
| 기준 | Prometheus + Grafana | CloudWatch Container Insights | Datadog |
|---|---|---|---|
| 비용 | 인프라 비용만 (오픈소스) | 수집량 기반 과금 | 호스트당 월 $15~23 |
| 커스터마이징 | PromQL로 자유롭게 | 제한적 | 중간 |
| 커뮤니티 | CNCF 졸업 프로젝트, 방대함 | AWS 문서 중심 | 벤더 문서 |
| 멀티 클라우드 | 가능 | AWS 전용 | 가능 |
| 운영 부담 | 높음 (직접 관리) | 낮음 | 낮음 |
| 추천 상황 | K8s 중심, 비용 민감, 커스텀 필요 | AWS 단일, 빠른 도입 | 예산 충분, 빠른 도입 |
비용에 민감하고 Kubernetes를 주 플랫폼으로 사용하는 환경이라면 Prometheus + Grafana가 적합합니다. 다만 운영 인력이 부족하다면 매니지드 서비스(Amazon Managed Prometheus, Grafana Cloud)를 검토할 수 있습니다.
2. 전체 아키텍처 구조
Prometheus + Grafana 모니터링 스택의 구성 요소와 데이터 흐름을 먼저 이해해야 합니다.
핵심 구성 요소
| 컴포넌트 | 역할 | 비유 |
|---|---|---|
| Prometheus Server | 메트릭 수집, 저장, 쿼리 처리 | 데이터 수집 엔진 |
| Grafana | 대시보드 시각화, 알림 UI | 관제 화면 |
| Alertmanager | 알림 라우팅, 그룹핑, 중복 제거 | 알림 관리자 |
| node-exporter | 노드(호스트) 레벨 메트릭 제공 | 서버 센서 |
| kube-state-metrics | Kubernetes 오브젝트 상태 메트릭 제공 | K8s 상태 보고자 |
| cAdvisor | 컨테이너 레벨 리소스 메트릭 | 컨테이너 센서 (kubelet 내장) |
데이터 흐름
Exporter/Kubelet → (Pull) Prometheus → (Query) Grafana
→ (Rules) Alertmanager → Slack/PagerDuty
Prometheus는 Pull 모델을 사용합니다. 각 타겟이 /metrics 엔드포인트를 노출하고, Prometheus가 주기적으로(기본 15초~30초) 가져갑니다. Push 모델(StatsD, CloudWatch Agent 등)과 달리 타겟이 Prometheus 주소를 알 필요가 없습니다.
Pull 모델의 장점과 한계
| 관점 | Pull 모델 장점 | Pull 모델 한계 |
|---|---|---|
| 서비스 디스커버리 | Prometheus가 타겟 목록을 관리 → 누락 감지 가능 | 타겟이 방화벽 뒤에 있으면 접근 불가 |
| 부하 제어 | Prometheus가 수집 주기 제어 → 과도한 메트릭 유입 방지 | 짧은 수명의 Job은 메트릭이 수집 전에 종료될 수 있음 |
| 디버깅 | 타겟의 /metrics를 직접 curl로 확인 가능 | - |
짧은 수명의 배치 Job은 Pushgateway를 사용해서 메트릭을 Push할 수 있습니다. 다만 Prometheus 공식 문서에서도 Pushgateway는 "서비스 레벨 배치 잡" 전용으로만 권장하며, 여러 소스의 메트릭을 수집하는 용도로 사용하면 단일 장애점이 될 수 있다고 경고합니다.
3. 설치: kube-prometheus-stack
왜 kube-prometheus-stack인가
Prometheus, Grafana, Alertmanager를 각각 설치할 수도 있지만, 운영 환경에서는 kube-prometheus-stack Helm 차트를 사용하는 것이 일반적입니다. 이유는 다음과 같습니다:
- Prometheus Operator 기반으로 CRD(ServiceMonitor, PodMonitor, PrometheusRule)를 통해 선언적 관리 가능
- node-exporter, kube-state-metrics, 기본 알림 규칙이 포함
- Grafana에 Kubernetes 대시보드가 사전 설정됨
- 컴포넌트 간 연동이 이미 구성되어 있음
사전 조건
- Kubernetes 클러스터 (v1.25 이상 권장)
- Helm v3 설치됨
- kubectl이 클러스터에 접근 가능
- 모니터링 전용 Namespace 생성 (권장)
설치 절차
# 1. Helm repo 추가
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 2. 모니터링 네임스페이스 생성
kubectl create namespace monitoring
# 3. kube-prometheus-stack 설치
helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--set prometheus.prometheusSpec.retention=15d \
--set prometheus.prometheusSpec.storageSpec.volumeClaimTemplate.spec.resources.requests.storage=50Gi \
--set grafana.adminPassword=<강력한-비밀번호> \
--set alertmanager.alertmanagerSpec.storage.volumeClaimTemplate.spec.resources.requests.storage=10Gi
주요 설정 옵션 설명
| 옵션 | 기본값 | 권장값 (운영) | 이유 |
|---|---|---|---|
| retention | 10d | 15d~30d | 장애 분석 시 최소 2주 데이터 필요 |
| storage | emptyDir | 50Gi PVC | Pod 재시작 시 데이터 유실 방지 |
| replicas | 1 | 2 (Prometheus) | 고가용성, 단 스토리지 2배 |
| scrapeInterval | 30s | 15s~30s | 15s 미만은 부하 대비 이득이 적음 |
설치 확인
# Pod 상태 확인
kubectl get pods -n monitoring
# 예상 출력:
# NAME READY STATUS RESTARTS
# kube-prometheus-stack-grafana-xxx 3/3 Running 0
# kube-prometheus-stack-kube-state-metrics-xxx 1/1 Running 0
# kube-prometheus-stack-operator-xxx 1/1 Running 0
# kube-prometheus-stack-prometheus-node-exporter-xxx 1/1 Running 0
# alertmanager-kube-prometheus-stack-alertmanager-0 2/2 Running 0
# prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0
# Grafana 접속 (포트 포워딩)
kubectl port-forward svc/kube-prometheus-stack-grafana 3000:80 -n monitoring
# 브라우저에서 http://localhost:3000 접속
# 기본 계정: admin / <설치 시 지정한 비밀번호>
4. 메트릭 수집 구조 이해
ServiceMonitor와 PodMonitor
Prometheus Operator는 ServiceMonitor와 PodMonitor CRD를 통해 스크레이핑 타겟을 관리합니다. Prometheus 설정 파일을 직접 수정할 필요가 없습니다.
# ServiceMonitor 예시: 특정 Service의 메트릭 수집
apiVersion: monitoring.coreos.io/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
namespace: monitoring
labels:
release: kube-prometheus-stack # Prometheus가 이 라벨로 탐색
spec:
namespaceSelector:
matchNames:
- production
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics # Service에 정의된 포트 이름
interval: 15s
path: /metrics
핵심 포인트: ServiceMonitor의 labels에 release: kube-prometheus-stack을 반드시 포함해야 합니다. Prometheus Operator가 이 라벨을 기준으로 ServiceMonitor를 탐색합니다. 이 라벨이 없으면 메트릭이 수집되지 않습니다.
Kubernetes 메트릭의 세 가지 계층
| 계층 | 제공자 | 주요 메트릭 | 용도 |
|---|---|---|---|
| 노드(Host) | node-exporter | CPU, 메모리, 디스크, 네트워크 | 인프라 용량 관리 |
| 컨테이너 | cAdvisor (kubelet) | 컨테이너별 CPU/메모리 사용량 | Pod 리소스 설계 |
| Kubernetes 오브젝트 | kube-state-metrics | Deployment 상태, Pod Phase, 레플리카 수 | 오케스트레이션 상태 감시 |
실무에서 자주 사용하는 메트릭
# 노드 CPU 사용률 (%)
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# Pod 메모리 사용률 (requests 대비)
container_memory_working_set_bytes{container!=""}
/ on(namespace, pod) kube_pod_container_resource_requests{resource="memory"} * 100
# Pod 재시작 횟수 (최근 1시간)
increase(kube_pod_container_status_restarts_total[1h]) > 0
# Deployment의 available 레플리카가 desired보다 적은 경우
kube_deployment_status_replicas_available < kube_deployment_spec_replicas
5. Grafana 대시보드 설계
USE 방법론 기반 설계
대시보드를 만들 때 "무엇을 보여줄 것인가"의 기준이 필요합니다. USE(Utilization, Saturation, Errors) 방법론을 적용하면 체계적으로 설계할 수 있습니다.
| 축 | 질문 | 예시 메트릭 |
|---|---|---|
| Utilization | 리소스가 얼마나 사용되고 있는가? | CPU 사용률, 메모리 사용률 |
| Saturation | 리소스가 포화 상태인가? 대기열이 쌓이는가? | CPU throttling, 디스크 I/O wait |
| Errors | 에러가 발생하고 있는가? | OOMKilled 횟수, CrashLoop 횟수 |
권장 대시보드 구성
kube-prometheus-stack을 설치하면 기본 대시보드가 포함되어 있습니다. 실무에서는 다음 대시보드를 추가로 구성합니다:
1. 클러스터 전체 현황 (Cluster Overview) - 노드 수, 전체 CPU/메모리 사용률, Pod 수 - 알림 발생 현황 요약 - 용도: 매일 아침 전체 상태 확인
2. 노드별 상세 (Node Detail) - 개별 노드 CPU, 메모리, 디스크, 네트워크 - Pod 분포, 리소스 압박 여부 - 용도: 노드 스케일링 판단
3. 네임스페이스별 리소스 (Namespace Resources) - 네임스페이스별 CPU/메모리 requests vs 실제 사용량 - 용도: 팀별 리소스 사용량 리포트, 낭비 감지
4. Pod/컨테이너 상세 (Pod Detail) - 개별 Pod의 CPU, 메모리, 네트워크, 재시작 횟수 - 용도: 특정 Pod 장애 분석
Grafana 대시보드 JSON 가져오기
커뮤니티에서 검증된 대시보드를 가져와서 시작하는 것이 효율적입니다.
# Grafana 대시보드 ID 예시 (grafana.com/dashboards에서 검색)
# - 315: Kubernetes Cluster Monitoring
# - 6417: Kubernetes Cluster (Prometheus)
# - 12740: Kubernetes Pod Monitoring
# - 1860: Node Exporter Full
Grafana UI에서 Import → Dashboard ID 입력 → 데이터소스 선택으로 바로 사용할 수 있습니다.
6. 알림 설계
알림의 원칙: 행동 가능한 알림만
알림 설계에서 가장 흔한 실수는 "일단 다 걸어놓자"입니다. CPU 50% 초과, 메모리 60% 초과 같은 알림을 설정하면 하루에 수십 개의 알림이 발생하고, 결국 모든 알림을 무시하게 됩니다. 이것이 알림 피로(Alert Fatigue)입니다.
좋은 알림의 조건: - 즉시 행동이 필요한 상황에만 발생 - 알림을 받은 사람이 무엇을 해야 하는지 알 수 있음 - 자동 복구되는 문제에는 알림을 걸지 않음 (예: HPA가 처리할 스케일링)
PrometheusRule 예시
apiVersion: monitoring.coreos.io/v1
kind: PrometheusRule
metadata:
name: kubernetes-critical-alerts
namespace: monitoring
labels:
release: kube-prometheus-stack
spec:
groups:
- name: kubernetes.critical
rules:
# Pod가 5분 이상 CrashLoopBackOff 상태
- alert: PodCrashLooping
expr: |
increase(kube_pod_container_status_restarts_total[1h]) > 5
for: 5m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }}가 반복 재시작 중"
description: "최근 1시간 동안 {{ $value }}회 재시작. 로그를 확인하세요."
runbook_url: "https://wiki.internal/runbook/pod-crash-looping"
# 노드 메모리 90% 초과 (10분 지속)
- alert: NodeMemoryHighUsage
expr: |
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) > 0.9
for: 10m
labels:
severity: critical
annotations:
summary: "노드 {{ $labels.instance }} 메모리 90% 초과"
description: "현재 {{ $value | humanizePercentage }} 사용 중. OOMKill 위험."
# Deployment 레플리카 부족 (5분 이상)
- alert: DeploymentReplicasMismatch
expr: |
kube_deployment_status_replicas_available
< kube_deployment_spec_replicas
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.namespace }}/{{ $labels.deployment }} 레플리카 부족"
description: "요청 {{ $labels.spec_replicas }}개 중 {{ $value }}개만 가용"
Alertmanager 라우팅 설정
# alertmanager 설정 (values.yaml에서 override)
alertmanager:
config:
global:
resolve_timeout: 5m
route:
receiver: 'slack-default'
group_by: ['alertname', 'namespace']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: 'slack-critical'
repeat_interval: 1h
- match:
severity: warning
receiver: 'slack-warning'
repeat_interval: 4h
receivers:
- name: 'slack-default'
slack_configs:
- api_url: '<SLACK_WEBHOOK_URL>'
channel: '#alerts-default'
- name: 'slack-critical'
slack_configs:
- api_url: '<SLACK_WEBHOOK_URL>'
channel: '#alerts-critical'
- name: 'slack-warning'
slack_configs:
- api_url: '<SLACK_WEBHOOK_URL>'
channel: '#alerts-warning'
설계 포인트: - group_by로 같은 유형의 알림을 묶어서 노이즈를 줄입니다 - repeat_interval로 동일 알림의 반복 주기를 조절합니다 (critical은 1시간, warning은 4시간) - runbook_url을 포함하면 알림을 받은 사람이 즉시 대응 절차를 확인할 수 있습니다
7. 운영 고려사항
스토리지와 보존 기간
Prometheus의 로컬 TSDB는 시계열 데이터를 효율적으로 저장하지만, 장기 보존에는 한계가 있습니다.
| 보존 기간 | 필요 스토리지 (예상) | 용도 |
|---|---|---|
| 7일 | ~20GB | 개발/테스트 환경 |
| 15일 | ~50GB | 일반 운영 환경 |
| 30일 | ~100GB | 용량 계획, 트렌드 분석 |
| 90일+ | Thanos/Cortex 필요 | 장기 분석, 컴플라이언스 |
주의: 위 수치는 일반적인 Kubernetes 클러스터(노드 5~10대, 시계열 수만~수십만 개) 기준 추정치입니다. 실제로는 메트릭 카디널리티(고유 라벨 조합 수), scrape interval, recording rule 수에 따라 크게 달라집니다.
장기 보존이 필요하면 Thanos 또는 Cortex를 도입합니다. Thanos는 기존 Prometheus에 Sidecar를 붙여서 S3/GCS에 장기 저장하는 방식이며, 기존 구조를 크게 변경하지 않아도 됩니다.
고가용성 구성
| 구성 | 장점 | 단점 |
|---|---|---|
| 단일 Prometheus | 단순, 리소스 절약 | SPOF, Pod 재시작 시 수집 공백 |
| Prometheus 2대 (동일 설정) | 한쪽 장애 시 다른 쪽 데이터 존재 | 스토리지 2배, 쿼리 중복 |
| Thanos + Prometheus | 장기 저장, 글로벌 뷰 | 복잡도 증가, 추가 컴포넌트 |
소규모 환경(노드 10대 이하)에서는 단일 Prometheus로 시작하고, PVC만 확실히 설정해두면 Pod 재시작 시에도 데이터를 보존할 수 있습니다. 규모가 커지면 Thanos Sidecar 방식으로 점진적 확장이 가능합니다.
리소스 설계
Prometheus 자체의 리소스 요구량을 고려해야 합니다:
# Prometheus 리소스 설정 예시 (values.yaml)
prometheus:
prometheusSpec:
resources:
requests:
cpu: 500m
memory: 2Gi
limits:
cpu: 2000m
memory: 4Gi
Prometheus의 메모리 사용량은 시계열당 약 3KB로 추정됩니다(Robust Perception 벤치마크 기준). 시계열 100만 개라면 약 3GB의 메모리가 필요합니다. 다만 이 수치는 scrape interval, 쿼리 복잡도, recording rule 수, 라벨 카디널리티에 따라 달라집니다.
보안 고려사항
- Grafana 접근 제어: RBAC 설정, SSO 연동 (OAuth2, LDAP)
- Prometheus 엔드포인트: 외부 노출 금지, NetworkPolicy로 monitoring 네임스페이스 내부 접근만 허용
- Secret 관리: Alertmanager의 Webhook URL, Grafana 비밀번호는 Kubernetes Secret으로 관리
# NetworkPolicy 예시: Prometheus 접근 제한
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: prometheus-allow-grafana-only
namespace: monitoring
spec:
podSelector:
matchLabels:
app.kubernetes.io/name: prometheus
ingress:
- from:
- podSelector:
matchLabels:
app.kubernetes.io/name: grafana
ports:
- port: 9090
8. 실무 시나리오: 처음부터 끝까지
시나리오: 스타트업 B2B SaaS (EKS, 노드 5대, 서비스 8개)
요구사항: - 비용을 최소화하면서 기본 모니터링 확보 - 장애 시 5분 이내 감지 - Slack으로 알림 수신 - 30일간 데이터 보존
설계 결정:
- 설치 방식: kube-prometheus-stack Helm 차트 (한 번에 전체 스택 배포)
- Prometheus: 단일 인스턴스 + 50Gi PVC (노드 5대 규모에서 HA는 과잉)
- 보존 기간: 15일 (30일 필요 시 Thanos 검토, 현재는 비용 우선)
- 대시보드: 기본 제공 대시보드 + Namespace별 리소스 대시보드 1개 추가
- 알림: Critical 5개, Warning 10개로 제한 (알림 피로 방지)
비용 추정: - Prometheus: 50Gi EBS gp3 ≈ $4/월 - Grafana: 10Gi EBS gp3 ≈ $0.8/월 - 추가 Pod 리소스: CPU 0.5코어, 메모리 2Gi (기존 노드 여유분 활용) - 합계: 월 $5~10 (Datadog이었다면 호스트 5대 × $15 = $75/월)
이 정도 규모에서는 모니터링 스택의 운영 부담이 크지 않습니다. 노드가 20대를 넘어가면 전담 인력이나 매니지드 서비스(Amazon Managed Prometheus + Amazon Managed Grafana)를 검토하는 것이 현실적입니다.
9. 트러블슈팅 체크리스트
| 증상 | 확인 사항 | 해결 방법 |
|---|---|---|
| ServiceMonitor 추가했는데 메트릭이 안 보임 | release: kube-prometheus-stack 라벨 확인 |
라벨 추가 후 Prometheus reload |
| Prometheus 메모리 OOM | 시계열 카디널리티 확인 (prometheus_tsdb_head_series) |
불필요한 메트릭 drop, relabeling |
| Grafana 대시보드 느림 | PromQL 쿼리 범위 확인 (7일 이상 조회 시) | 쿼리 범위 축소, recording rule 추가 |
| 알림이 안 옴 | Alertmanager route 설정 확인 | amtool config routes test 명령으로 라우팅 테스트 |
| 노드 메트릭 누락 | node-exporter DaemonSet 상태 확인 | toleration 설정 확인 (taint된 노드) |
10. 다음 단계
이 글에서 다룬 내용은 Prometheus + Grafana 스택의 기본 구성입니다. 운영 환경에서 더 깊이 들어가려면 아래 주제를 순서대로 학습하는 것을 추천합니다:
- PromQL 실전 쿼리 패턴 — rate, irate, histogram_quantile 등 실무 쿼리 작성법
- 알림 설계 원칙 — SLI/SLO 기반 알림, 노이즈 줄이기
- 장기 저장: Thanos — S3 연동, 글로벌 뷰, 다운샘플링
- 커스텀 메트릭 수집 — 애플리케이션에서 /metrics 엔드포인트 구현
- Observability as Code — Terraform으로 대시보드와 알림 규칙 관리
관련 글
'Observability' 카테고리의 다른 글
| 알림 설계: 노이즈를 줄이고 의미 있는 알림만 받는 방법 (0) | 2026.06.07 |
|---|---|
| CloudWatch vs Datadog vs Grafana: 모니터링 도구 선택 기준 (0) | 2026.06.01 |
| Observability란 무엇인가: Monitoring, Logging, Tracing의 차이 (0) | 2026.05.31 |