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을 초과했습니다"
- 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에 도달
정리
Kubernetes 모니터링은 Metrics Server(실시간) + Prometheus(시계열) + Grafana(시각화) + AlertManager(알림)로 구성됩니다. kube-state-metrics로 오브젝트 상태를, Node Exporter로 인프라 메트릭을, ServiceMonitor로 애플리케이션 메트릭을 수집합니다. RED/USE 방법론에 따라 핵심 메트릭을 모니터링하고, 적절한 알림을 설정하면 장애를 사전에 감지하고 빠르게 대응할 수 있습니다.