Kubernetes 모니터링 — Prometheus와 Grafana로 클러스터 상태를 파악하는 방법
클러스터에서 Pod이 재시작을 반복하고 있는데, 원인이 메모리 부족인지 CPU 쓰로틀링인지 어떻게 알 수 있을까요?
kubectl top으로 현재 상태는 볼 수 있지만, "30분 전에 무슨 일이 있었는지"는 알 수 없습니다. 시계열 모니터링 시스템이 없으면 장애 원인을 사후에 분석하는 것이 불가능합니다. Prometheus와 Grafana는 Kubernetes 모니터링의 사실상 표준입니다.
모니터링 계층
Kubernetes 모니터링은 크게 세 계층으로 나뉩니다.
| 계층 | 수집 대상 | 도구 |
|---|---|---|
| 인프라 | 노드 CPU/메모리/디스크/네트워크 | Node Exporter |
| ** 클러스터** | 오브젝트 상태 (Pod, Deployment 등) | kube-state-metrics |
| ** 애플리케이션** | 요청 수, 응답 시간, 에러율 | 커스텀 메트릭 |
Metrics Server — kubectl top의 기반
Metrics Server는 kubelet의 cAdvisor에서 메트릭을 수집하여 API로 제공합니다. HPA와 kubectl top이 이를 사용합니다.
# 설치
kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
# 사용
kubectl top nodes
# NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
# node-1 350m 17% 2048Mi 51%
kubectl top pods -n production
# NAME CPU(cores) MEMORY(bytes)
# web-abc 120m 256Mi
Metrics Server는 ** 현재 시점의 메트릭만** 제공합니다. 과거 데이터를 저장하지 않으므로 모니터링 시스템은 별도로 필요합니다.
Prometheus — 시계열 모니터링
Prometheus는 pull 방식으로 메트릭을 수집하고, 시계열 데이터베이스에 저장하며, PromQL로 쿼리합니다.
아키텍처
대상(Pod, Node) ←── 스크레이핑 ── Prometheus Server ──→ Grafana
↑ ↓
/metrics 엔드포인트 AlertManager ──→ Slack, PagerDuty
Prometheus Operator 설치 (kube-prometheus-stack)
# Helm으로 한 번에 설치 (Prometheus + Grafana + AlertManager + Exporters)
helm install monitoring prometheus-community/kube-prometheus-stack \
--namespace monitoring \
--create-namespace \
--set grafana.adminPassword=admin
이 스택에는 다음이 포함됩니다.
- Prometheus Server
- Grafana (사전 구성된 대시보드 포함)
- AlertManager
- Node Exporter (각 노드의 메트릭)
- kube-state-metrics (Kubernetes 오브젝트 메트릭)
kube-state-metrics
Kubernetes API를 통해 오브젝트의 상태를 메트릭으로 변환합니다.
# Pod 상태 메트릭
kube_pod_status_phase{namespace="production",pod="web-abc",phase="Running"} 1
kube_pod_container_status_restarts_total{namespace="production",pod="web-abc"} 3
# Deployment 상태
kube_deployment_status_replicas_available{deployment="web"} 3
kube_deployment_spec_replicas{deployment="web"} 3
# 리소스 요청/제한
kube_pod_container_resource_requests{resource="cpu"} 0.2
kube_pod_container_resource_limits{resource="memory"} 536870912
ServiceMonitor — 선언적 스크레이핑 설정
Prometheus Operator를 사용하면 ServiceMonitor CRD로 스크레이핑 대상을 정의합니다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
namespace: monitoring
labels:
release: monitoring # Prometheus가 이 레이블로 ServiceMonitor를 찾음
spec:
namespaceSelector:
matchNames:
- production
selector:
matchLabels:
app: my-app
endpoints:
- port: metrics # Service의 포트 이름
interval: 15s
path: /metrics
애플리케이션이 /metrics 엔드포인트에서 Prometheus 형식의 메트릭을 노출해야 합니다.
# Prometheus 메트릭 형식 예제
# HELP http_requests_total Total number of HTTP requests
# TYPE http_requests_total counter
http_requests_total{method="GET",status="200"} 12345
http_requests_total{method="POST",status="201"} 678
# HELP http_request_duration_seconds HTTP request latency
# TYPE http_request_duration_seconds histogram
http_request_duration_seconds_bucket{le="0.1"} 8000
http_request_duration_seconds_bucket{le="0.5"} 11000
http_request_duration_seconds_bucket{le="1.0"} 12000
PromQL — 핵심 쿼리
CPU 관련
# 네임스페이스별 CPU 사용률
sum(rate(container_cpu_usage_seconds_total{namespace="production"}[5m])) by (pod)
# CPU 쓰로틀링 비율
sum(rate(container_cpu_cfs_throttled_periods_total[5m]))
/ sum(rate(container_cpu_cfs_periods_total[5m]))
메모리 관련
# 메모리 사용량 (limit 대비)
container_memory_working_set_bytes{namespace="production"}
/ container_spec_memory_limit_bytes{namespace="production"}
# OOMKill 발생 횟수
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"}
Pod 상태
# 재시작 횟수가 많은 Pod
kube_pod_container_status_restarts_total > 5
# Running이 아닌 Pod
kube_pod_status_phase{phase!="Running",phase!="Succeeded"} == 1
# Pending 상태 Pod
kube_pod_status_phase{phase="Pending"} == 1
AlertManager — 알림 설정
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: pod-alerts
namespace: monitoring
labels:
release: monitoring
spec:
groups:
- name: pod-health
rules:
- alert: PodCrashLooping
expr: rate(kube_pod_container_status_restarts_total[15m]) > 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Pod {{ $labels.pod }}이 반복적으로 재시작 중"
description: "15분간 재시작 비율이 0.1을 초과했습니다"
메모리 사용률 같은 리소스 기반 알림도 함께 설정하면 OOM Kill을 사전에 감지할 수 있습니다.
- alert: HighMemoryUsage
expr: |
container_memory_working_set_bytes / container_spec_memory_limit_bytes > 0.9
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.pod }}의 메모리 사용률이 90%를 초과"
Grafana 대시보드
kube-prometheus-stack을 설치하면 사전 구성된 대시보드가 포함됩니다.
| 대시보드 | 내용 |
|---|---|
| Kubernetes / Cluster | 클러스터 전체 리소스 현황 |
| Kubernetes / Nodes | 노드별 CPU, 메모리, 디스크, 네트워크 |
| Kubernetes / Pods | Pod별 리소스 사용량, 재시작 |
| Kubernetes / Namespace | 네임스페이스별 리소스 |
# Grafana 접근 (포트포워딩)
kubectl port-forward svc/monitoring-grafana -n monitoring 3000:80
# 브라우저에서 http://localhost:3000 접속
# 기본 계정: admin / admin (또는 설정한 비밀번호)
커스텀 대시보드에 포함할 핵심 패널
- ** 요청률(RPS)**: 서비스별 초당 요청 수
- ** 에러율 **: 4xx/5xx 비율
- ** 레이턴시 **: P50, P95, P99 응답 시간
- ** 리소스 **: CPU/메모리 사용률 vs requests/limits
- **Pod 상태 **: Running/Pending/Failed 수, 재시작 횟수
모니터링 Best Practices
RED 방법 (서비스 모니터링)
- Rate: 초당 요청 수
- Errors: 에러 비율
- Duration: 응답 시간
USE 방법 (인프라 모니터링)
- Utilization: 리소스 사용률
- Saturation: 포화도 (큐 길이 등)
- Errors: 에러 수
핵심 알림 설정
[즉시 대응]
- Pod CrashLoopBackOff
- 노드 NotReady
- 디스크 사용률 > 90%
[주의]
- CPU 쓰로틀링 비율 > 25%
- 메모리 사용률 > 85%
- HPA가 maxReplicas에 도달
주의할 점
1. 카디널리티가 높은 라벨을 쓰면 Prometheus가 OOM으로 죽는다
user_id나 request_id처럼 값이 무한히 늘어나는 라벨을 메트릭에 붙이면 시계열 데이터가 폭증합니다. Prometheus의 메모리 사용량이 급격히 증가하여 OOM Kill이 발생하고, 모니터링 자체가 중단됩니다. 라벨은 반드시 유한한 값(status_code, method, endpoint 등)만 사용하세요.
2. 알림 규칙의 for 기간을 너무 짧게 설정하면 알림 폭탄을 맞는다
CPU 사용률이 잠깐 튀는 것은 정상적인 상황인데, for: 0s나 for: 30s로 설정하면 매번 알림이 발생합니다. 알림 피로(alert fatigue)가 쌓이면 진짜 중요한 알림도 무시하게 됩니다. 일반적으로 for: 5m 이상으로 설정하여 일시적 스파이크를 필터링하세요.
3. Prometheus의 retention 기간과 디스크 용량을 계산하지 않으면 스토리지가 가득 찬다
기본 retention이 15일인데, 메트릭 수가 많은 클러스터에서는 이것만으로도 수백 GB가 필요할 수 있습니다. 디스크가 가득 차면 Prometheus가 새 데이터를 쓰지 못하고 모니터링이 중단됩니다. --storage.tsdb.retention.size로 최대 용량을 제한하고, 장기 데이터는 Thanos나 Cortex 같은 원격 스토리지로 옮기세요.
정리
Kubernetes 모니터링은 Metrics Server(실시간) + Prometheus(시계열) + Grafana(시각화) + AlertManager(알림)로 구성됩니다. kube-state-metrics로 오브젝트 상태를, Node Exporter로 인프라 메트릭을, ServiceMonitor로 애플리케이션 메트릭을 수집합니다. RED/USE 방법론에 따라 핵심 메트릭을 모니터링하고, 적절한 알림을 설정하면 장애를 사전에 감지하고 빠르게 대응할 수 있습니다.