10.2 메트릭
클러스터의 메트릭 질문은 두 갈래로 나뉜다. “이 컨테이너가 CPU와 메모리를 얼마나 쓰고 있는가"라는 사용량 질문과, “이 Deployment의 replica가 몇 개 준비됐고 이 Pod가 몇 번 재시작했는가"라는 상태 질문이다. Kubernetes 생태계는 이 둘을 서로 다른 컴포넌트로 답한다. 사용량은 cAdvisor와 metrics-server의 계보가, 상태는 kube-state-metrics가 담당한다. 이 구분을 알아야 어떤 지표를 어디서 가져올지 헤매지 않는다.
리소스 메트릭 파이프라인
사용량 수치의 원천은 cgroup이다. kubelet에 내장된 cAdvisor가 노드의 cgroup 파일시스템에서 컨테이너별 CPU 사용 시간과 메모리 워킹셋을 읽어, kubelet의 /metrics/cadvisor와 /metrics/resource 엔드포인트로 노출한다. container_cpu_usage_seconds_total, container_memory_working_set_bytes 같은 지표가 여기서 나온다.
metrics-server는 이 kubelet 엔드포인트를 주기적으로(기본 15초) 수집해 리소스 메트릭 API(metrics.k8s.io)로 제공하는 클러스터 애드온이다. kubectl top이 바로 이 API의 소비자다.
kubectl top nodes
kubectl top pods -n production --containers
flowchart TD
CG["cgroup"] --> CA["cAdvisor<br/>(kubelet 내장)"]
CA --> MS["metrics-server"]
MS --> API["리소스 메트릭 API"]
API --> TOP["kubectl top"]
API --> HPA["HPA"]
metrics-server의 성격을 정확히 아는 것이 중요하다. 최신 값만 메모리에 유지하고 이력을 남기지 않으므로, “지금 얼마나 쓰는가"에는 답해도 “어제 이 시간에는 얼마였나"에는 답하지 못한다. 공식 문서도 metrics-server를 autoscaling 이외의 용도로 쓰지 말고 모니터링 솔루션의 지표 원천으로 삼지 말라고 안내한다. 이력이 필요한 모니터링은 Prometheus 같은 시계열 시스템이 kubelet 엔드포인트를 직접 수집하는 구성으로 해결한다.
kube-state-metrics: 오브젝트 상태를 메트릭으로
kube-state-metrics는 이름 때문에 metrics-server와 자주 혼동되지만 하는 일이 전혀 다르다. API server를 watch하면서 Kubernetes 오브젝트의 상태를 Prometheus 형식 메트릭으로 변환하는 서비스이며, 리소스 사용량은 다루지 않는다.
kube_pod_status_phase{phase="Pending"} # Pod가 어느 phase에 있는가
kube_pod_container_status_restarts_total # 컨테이너 재시작 누계
kube_deployment_status_replicas_available # Deployment의 가용 replica 수
kube_node_status_condition{condition="Ready"} # 노드 Ready 조건두 컴포넌트를 대조하면 다음과 같다.
| metrics-server | kube-state-metrics | |
|---|---|---|
| 데이터 원천 | kubelet(cAdvisor) | API server watch |
| 다루는 것 | CPU/메모리 사용량 | 오브젝트 상태 |
| 저장 | 인메모리 최신 값 | 저장 없음(변환만) |
| 주 소비자 | kubectl top, HPA | Prometheus |
kube-state-metrics 자체는 아무것도 저장하지 않는다. /metrics 엔드포인트를 노출할 뿐이고, 축적과 질의는 이를 수집하는 Prometheus의 몫이다.
Prometheus 스크레이프와 ServiceMonitor
Prometheus는 pull 모델로 동작한다. 대상이 /metrics HTTP 엔드포인트로 지표를 노출하면 Prometheus가 주기적으로 가져간다(스크레이프). Kubernetes 환경에서 이 모델의 관건은 대상 목록의 유지다. Pod는 계속 생기고 사라지므로 정적 설정으로는 따라갈 수 없고, Prometheus의 kubernetes_sd_configs가 API server에서 Pod와 Service를 조회해 스크레이프 대상을 동적으로 발견한다.
Prometheus Operator를 쓰는 환경에서는 이 발견 규칙을 ServiceMonitor라는 CRD로 선언한다. label selector로 Service를 선택하면 Operator가 해당하는 스크레이프 설정을 생성해 Prometheus에 반영한다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: web-app
spec:
selector:
matchLabels:
app: web
endpoints:
- port: metrics
interval: 30s애플리케이션 배포와 모니터링 등록이 같은 문법(label과 selector)으로 묶이므로, 새 서비스를 추가할 때 Prometheus 설정 파일을 직접 수정할 일이 없어진다.
무엇을 경보로 삼나
지표가 수천 개 쌓여도 경보 없이는 아무도 보지 않는다. 반대로 모든 것에 경보를 걸면 노이즈에 묻혀 진짜 장애를 놓친다. 우선순위가 높은 것은 세 부류다.
첫째는 용량이다. 노드 CPU/메모리 포화, PVC 사용률, 노드별 Pod 수 한도가 여기 속한다. 용량 문제는 한 번 터지면 여러 워크로드가 동시에 영향을 받고, eviction이 연쇄되면 수습 비용이 커진다. 여유가 남아 있을 때 미리 알아야 하는 대표적인 지표다.
둘째는 재시작 횟수다. kube_pod_container_status_restarts_total의 증가율에 경보를 걸면 CrashLoopBackOff로 굳어지기 전의 간헐적 크래시가 드러난다. 재시작 자체는 Kubernetes가 복구해 주므로 서비스 증상이 없을 때가 많은데, 그래서 오히려 경보 없이는 아무도 모른 채 지나간다.
셋째는 Pending 체류다. kube_pod_status_phase{phase="Pending"}이 일정 시간 이상 지속되면 스케줄링이 막힌 것이다. 자원 부족이든 taint 불일치든 PVC 대기든 사람이 개입해야 풀리는 경우가 대부분이라 경보 가치가 높다. requests와 스케줄링의 배경은 Part VIII. 스케줄링과 자원 관리에서 다뤘고, 패턴별 진단 절차는 이 Part의 마지막 챕터에 있다.
정리
사용량은 cgroup에서 cAdvisor와 metrics-server를 거쳐 kubectl top으로 이어지는 짧은 파이프라인이고, 이력이 없는 실시간 값이다. 상태는 kube-state-metrics가 API server의 오브젝트를 메트릭으로 변환하고 Prometheus가 수집해 축적한다. 경보는 용량, 재시작 증가율, Pending 체류처럼 사람이 개입해야 하는 신호부터 건다.