Theme:

클러스터에서 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이 이를 사용합니다.

SHELL
# 설치
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로 쿼리합니다.

아키텍처

PLAINTEXT
대상(Pod, Node) ←── 스크레이핑 ── Prometheus Server ──→ Grafana
       ↑                              ↓
  /metrics 엔드포인트          AlertManager ──→ Slack, PagerDuty

Prometheus Operator 설치 (kube-prometheus-stack)

SHELL
# 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를 통해 오브젝트의 상태를 메트릭으로 변환합니다.

PLAINTEXT
# 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로 스크레이핑 대상을 정의합니다.

YAML
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 형식의 메트릭을 노출해야 합니다.

PLAINTEXT
# 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 관련

PROMQL
# 네임스페이스별 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]))

메모리 관련

PROMQL
# 메모리 사용량 (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 상태

PROMQL
# 재시작 횟수가 많은 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 — 알림 설정

YAML
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 / PodsPod별 리소스 사용량, 재시작
Kubernetes / Namespace네임스페이스별 리소스
SHELL
# Grafana 접근 (포트포워딩)
kubectl port-forward svc/monitoring-grafana -n monitoring 3000:80

# 브라우저에서 http://localhost:3000 접속
# 기본 계정: admin / admin (또는 설정한 비밀번호)

커스텀 대시보드에 포함할 핵심 패널

  1. 요청률(RPS): 서비스별 초당 요청 수
  2. 에러율: 4xx/5xx 비율
  3. 레이턴시: P50, P95, P99 응답 시간
  4. 리소스: CPU/메모리 사용률 vs requests/limits
  5. Pod 상태: Running/Pending/Failed 수, 재시작 횟수

모니터링 Best Practices

RED 방법 (서비스 모니터링)

  • Rate: 초당 요청 수
  • Errors: 에러 비율
  • Duration: 응답 시간

USE 방법 (인프라 모니터링)

  • Utilization: 리소스 사용률
  • Saturation: 포화도 (큐 길이 등)
  • Errors: 에러 수

핵심 알림 설정

PLAINTEXT
[즉시 대응]
- Pod CrashLoopBackOff
- 노드 NotReady
- 디스크 사용률 > 90%

[주의]
- CPU 쓰로틀링 비율 > 25%
- 메모리 사용률 > 85%
- HPA가 maxReplicas에 도달

정리

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

댓글 로딩 중...