관측성

K8s 관측

meellon 2026. 7. 1. 05:50

학습 목표

K8s 메트릭 3층(클러스터 상태 · 컨테이너 자원 · 앱 RED)을 구분해 설명할 수 있다.

kube-state-metricscAdvisor(kubelet 경유)가 무엇을 노출하는지 설명할 수 있다.

metrics-server(HPA)와 관측 스택(Prometheus)의 역할 차이를 설명할 수 있다.

Prometheus kubernetes_sd·ServiceMonitor로 K8s target을 scrape하도록 구성할 수 있다.

장애 triage에서 어느 층의 메트릭·로그·트레이스를 먼저 볼지 판단할 수 있다.

문제 상황

  • kubectl get pods모두 Running — 그런데 checkout 5xx 100%
    • Pod phase앱 SLI다른 신호
  • Grafana CPU 패널 90% — on-call이 scale out — 근본은 DB connection pool
    • 인프라 메트릭만 보면 앱 장애를 놓친다
  • Deployment replicas 3인데 실제 ready 1 — HPA는 Unknown
    • kube-state-metrics 없으면 desired vs ready gap이 안 보인다
  • Prometheus target up=0 — Pod IP 바뀔 때마다 수동 yaml 수정
    • kubernetes_sd·annotation 표준 없음
  • metrics-server kubectl top은 되는데 SLO burn rate 알람 없음
    • HPA용 summary API시계열 관측

Platform에서 Pod·HPA·metrics-server를 봤다. Observability 시리즈에서 Prometheus·Grafana·SLO·runbook까지 갖췄다. K8s 위에서 신호를 한곳에 모으는 마지막 본편이다.

1. K8s 메트릭 3층

수집원 대표 메트릭 질문
Cluster state kube-state-metrics kube_pod_status_phase, kube_deployment_status_replicas_available desired 맞나? CrashLoop?
Container resources cAdvisor (kubelet :10250/metrics/cadvisor) container_cpu_usage_seconds_total, container_memory_working_set_bytes OOM·throttle·saturation?
Application /metrics http_requests_total, histogram RED·SLO·사용자 영향?
증상별 첫 화면 (예):
  page "API 5xx"     → 앱 RED (층 3) → trace/log (11편)
  "Pod not ready"    → kube-state-metrics (층 1)
  OOMKilled / throttle → cAdvisor + limits (층 2)
  • node-exporter — 노드 OS·디스크·네트워크 (USE). cAdvisor와 보완
  • kubelet·apiserver·etcd 메트릭 — control plane 건강 (운영 클러스터)
  • 앞서 RED·USE — 층 3은 서비스, 층 2·node는 인프라

2. metrics-server vs 관측 스택

  metrics-server Prometheus + exporters
목적 kubectl top, HPA Resource metric 대시보드·SLO·알람·장기 보관
데이터 kubelet summary API (최근 스냅) 시계열 scrape·retention
주기 ~15s (HPA loop) scrape_interval 15~30s + recording rule
라벨 namespace·pod (top용) PromQL·relabel·join
  • Platform HPArequests.cpu + metrics-server 필수 (스케줄링 편)
  • Custom metrics HPA — Prometheus adapter로 QPS·queue depth (Observability 연동)
  • 같은 CPU 숫자를 두 시스템이 보더라도 용도가 다르다 — 대체가 아니라 병행

3. kube-state-metrics

kube-state-metrics(KSM) — API server 객체를 watch상태를 Prometheus 메트릭으로 노출한다.

메트릭 패밀리 의미
kube_pod_status_phase Pending / Running / Failed / …
kube_pod_container_status_restarts_total 컨테이너 restart 누적
kube_deployment_status_replicas_* desired · available · unavailable
kube_node_status_condition Ready, MemoryPressure, …
kube_job_status_failed Job 실패
# Ready 아닌 Pod (namespace=api)
sum(kube_pod_status_phase{phase!="Running", namespace="api"}) by (pod, phase)

# Deployment available < spec replicas
(
  kube_deployment_spec_replicas
  - kube_deployment_status_replicas_available
) > 0
  • KSM은 클러스터당 1 (또는 sharded) — 고카디널리티 주의 (8편)
  • kube_* 라벨에 namespace, pod, deployment — runbook 필터에 사용
  • CrashLoopBackOff — restart metric ↑ + kubectl logs (로그 편)

4. cAdvisor · kubelet

cAdvisor — kubelet에 내장. 컨테이너별 CPU·메모리·네트워크·filesystem 사용량.

메트릭 용도
container_cpu_usage_seconds_total CPU 사용 (rate → cores)
container_memory_working_set_bytes OOM 판단에 가까운 working set
container_spec_memory_limit_bytes limits와 비교
container_network_* Pod egress/ingress
# memory working set / limit (Burstable OOM 위험)
container_memory_working_set_bytes{namespace="api", container="api"}
/ container_spec_memory_limit_bytes > 0.85

# CPU throttle (limits 있을 때)
rate(container_cpu_cfs_throttled_seconds_total{namespace="api"}[5m]) > 0
  • container="POD"·pause — 쿼리에서 제외 (container!="", container!="POD")
  • requests/limits 없으면 saturation 해석 불가 — Platform QoS와 함께
  • kubectl top ≈ summary API — PromQL 추세·알람은 Prometheus 경로

5. Prometheus scrape on K8s

수집 경로

Target job / Operator 포트·경로
kube-state-metrics static 또는 ServiceMonitor :8080/metrics
node-exporter DaemonSet + ServiceMonitor :9100/metrics
kubelet/cAdvisor kubernetes-nodes-cadvisor job apiserver proxy 또는 kubelet auth
앱 Pod kubernetes-pods SD 또는 PodMonitor annotation 또는 port name
# Pod annotation (발췌) — code/pod-annotations.example
metadata:
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "8080"
    prometheus.io/path: "/metrics"
# kubernetes_sd — code/prometheus-k8s-scrape.yaml (발췌)
- job_name: kubernetes-pods
  kubernetes_sd_configs:
    - role: pod
  relabel_configs:
    - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    - source_labels: [__meta_kubernetes_pod_label_app]
      target_label: app
    - source_labels: [__meta_kubernetes_namespace]
      target_label: namespace

Prometheus Operator

운영에서는 kube-prometheus-stackServiceMonitor·PodMonitor CRD로 scrape 선언.

# code/servicemonitor-api.yaml (발췌)
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: api
  labels:
    release: prometheus   # Operator selector
spec:
  selector:
    matchLabels:
      app: api
  endpoints:
    - port: metrics
      interval: 15s
      path: /metrics
방식 장점
annotation + SD 앱 팀이 Pod yaml만 수정
ServiceMonitor RBAC·네임스페이스별 분리, GitOps
PodMonitor Service 없이 직접 Pod port
  • scrape 실패 → up{job="..."} == 0앞서 Prometheus
  • relabel으로 pod, node, app — SLO·runbook 변수와 맞춤

6. 대시보드 · 알람 연결

Grafana 변수: $namespace, $deployment, $pod — kube-state + 앱 RED 한 보드.

패널 PromQL / 소스
Availability 앱 RED error rate (12편 SLO)
Replicas gap spec - available (KSM)
Restarts increase(kube_pod_container_status_restarts_total[1h])
Memory headroom working set / limit (cAdvisor)
Burn rate recording rule (12편)
# alert annotation — runbook 연결 (13편)
annotations:
  summary: "Deployment api ready replicas below spec for 10m"
  runbook_url: "https://wiki.example/runbooks/deployment-not-ready"
  dashboard: "https://grafana/d/k8s-api"
  • 앞서 alert-runbook — K8s alert도 증상·first steps 필수
  • Pod restart 알람 단독 page — cardinality·flapping (8편) — 임계값·for: 조정

더 많은 쿼리: code/k8s-promql.promql

7. 장애 triage 흐름

사용자 증상 1순위 2순위 3순위
5xx·latency 앱 RED + trace (11편) 최근 deploy annotation Pod ready (KSM)
Intermittent fail trace + log correlation readiness probe node NotReady
Slow only histogram p99 CPU throttle (cAdvisor) node disk
Total outage SLO burn (12편) replicas available ingress·Service (Platform)
Mitigate (13편):
  replicas 0  → rollback Deployment / scale previous
  node drain  → cordon + reschedule
  OOM loop    → limits↑ 임시 + traffic shift
  • Infrastructure alert(CPU 80%) vs SLO page — severity impact 기준 (13편)
  • control plane(api server down) — kubectl 자체 실패 — managed 클러스터 runbook 별도

8. 실무 체크리스트

항목 권장
3층 KSM + cAdvisor + 앱 RED하나라도 빠지면 blind spot
HPA metrics-server 유지 — Prometheus와 역할 분리
scrape ServiceMonitor 표준 + up 알람
labels namespace, app, pod — runbook·Grafana 변수 통일
limits requests/limits 설정 — cAdvisor 해석 전제
cardinality pod 라벨 join — high-cardinality alert 금지 (8편)
OTel DaemonSet agent — trace + infra log (10편)
kubectl top pods -n api              # metrics-server (HPA 경로)
kubectl get --raw /api/v1/nodes/NODE/proxy/metrics/cadvisor | head
curl -s kube-state-metrics:8080/metrics | grep kube_deployment
promtool check rules rules/*.yaml

9. 정리

  • K8s 관측은 cluster state(KSM) · container(cAdvisor) · app RED 3층
  • metrics-server는 HPA·top — SLO·알람은 Prometheus 관측 스택
  • scrape는 kubernetes_sd 또는 ServiceMonitor — Pod IP 변경에 내성
  • triage는 사용자 impact(SLO) 먼저 — 인프라 CPU는 보조
  • 다음 — Observability Series를 마치며 (에필로그)

다음에 다룰 것

  • 시리즈 전체 개념 지도
  • Observability 확장·학습 경로

해당 내용은 Observability Engineering (Charity Majors, Liz Fong-Jones, George Miranda), Prometheus Operator Documentation (prometheus-operator.dev), Kubernetes Documentation 의 내용을 기반으로 합니다.

'관측성' 카테고리의 다른 글

Observability Series를 마치며  (0) 2026.07.02
온콜과 인시던트  (0) 2026.06.30
SLO와 에러 버짓  (0) 2026.06.29
트레이스와 로그·메트릭 연계  (0) 2026.06.28
OpenTelemetry  (0) 2026.06.27