IL-0176 LINE · 2020-07-10 (게시일)kubernetesobservability
클러스터는 쿠버네티스 1.13.5 에 노드 235개, 컨트롤 플레인 노드 7개, etcd 노드 5개로 이루어져 있었고 모든 노드가 VM 이었다. Prometheus 2.14.0 서버는 vCPU 4개, 메모리 8GB, 스와프를 끈 호스트에서 돌았다. 이 Prometheus 파드가 CrashLoopBackOff 에 빠져 950번 재시작했다. 종료 코드 137 은 프로세스가 SIGKILL 을 받았다는 뜻이다.
kubelet 로그의 OOM 이벤트는 cAdvisor 가 /dev/kmsg 에서 커널의 OOM 메시지를 읽어 kubelet 의 oom_watcher 로 넘긴 것이었다. 컨테이너를 죽인 것은 kubelet 이 아니라 커널의 OOM Killer 였다. 시계열 수로 추정한 메모리 사용량은 5.7GB 로, 시작하고 5분 만에 8GB 호스트가 감당하기 어려운 수준이 됐다. docker restart 로 재현해 보니 컨테이너가 다시 뜬 뒤 호스트 메모리를 거의 다 쓰고 OOM 으로 죽었다.
OOM Killer 는 oom_score 가 가장 높은 프로세스를 고르는데, Prometheus 컨테이너의 oom_score_adj 는 999 였다. SystemTap 으로 지켜보니 실행 중에 이 값을 바꾸는 프로세스는 없었고, 커널은 값을 지정하지 않은 프로세스에 0 을 줬다. 값은 kubelet 이 CRI 요청에 담아 containerd 에 넘긴 것이었다. 파드 매니페스트에서 configmap-reload 컨테이너에만 requests 와 limits 가 있어 파드는 Burstable QoS 로 분류됐다. kubelet 은 Burstable 컨테이너의 oom_score_adj 를 1000 에서 메모리 요청 비율을 빼서 계산한다. 메모리 요청이 없는 Prometheus 컨테이너는 계산값이 Best-Effort 와 같은 1000 이 됐고, kubelet 이 여기서 1 을 빼 999 를 줬다. 그래서 메모리가 모자랄 때 가장 먼저 죽는 대상이 됐다. Prometheus configMap 에서 불필요한 설정 대부분을 지우자 컨테이너는 더 이상 비정상 종료되지 않았다.
어느 월요일 아침, 엔지니어가 쿠버네티스 클러스터 경고를 보려고 Prometheus 대시보드를 열었는데 접속되지 않았다. Prometheus 서버 파드는 CrashLoopBackOff 상태였다.
kubectl get pods 출력에는 cluster-monitoring-Prometheus-d56bb6d46-tzmcj 1/2 CrashLoopBackOff 950 3d20h <IP> worker3 이 찍혔다. kubectl describe 로 보니 configmap-reload 컨테이너는 Running 이었다. Prometheus 컨테이너는 State: Waiting, Reason: CrashLoopBackOff 였고 마지막 상태는 Reason: Error, Exit Code: 137 이었다.
처음에는 디스크를 의심했다. 예전에 수집 지표가 가용 디스크를 넘어 Prometheus 가 비정상 종료된 적이 있었기 때문이다. 하지만 30Gi PVC 의 사용률은 35% 로 넉넉했다. Prometheus 로그에도 눈에 띄는 오류는 없었다. 마지막 로그는 "replaying WAL, this may take awhile" 와 "WAL segment loaded" 였고, WAL 을 메모리로 리플레이하던 중에 죽은 것이었다.
호스트의 kubelet 로그에는 Readiness probe 실패 "HTTP probe failed with statuscode: 503", "Got sys oom event from cadvisor", Liveness probe 실패 "read: connection reset by peer", 그리고 ContainerDied 이벤트가 차례로 찍혔다. Grafana 대시보드를 보니 Prometheus 가 시작하고 5분 만에 시계열 수가 2,162,256 까지 뛰었다.
원인 용량 한계
월요일 아침 엔지니어가 클러스터 경고를 확인하려고 Prometheus 대시보드를 열었다가 접속되지 않는 것을 보고 알았다.
원인은 둘이었다. 첫째, Prometheus 파드의 requests 와 limits 를 잘못 잡아 Prometheus 서버 컨테이너가 높은 oom_score_adj 를 받았다. 둘째, 대규모 클러스터에서 Prometheus 가 쓸 메모리를 미리 예측하지 않았다. 쿠버네티스에서 파드의 QoS 클래스는 메모리가 모자랄 때 어느 컨테이너가 먼저 죽는지에 영향을 준다. 커널의 OOM Killer 는 메모리 사용량과 oom_score_adj 로 점수를 매기고, kubelet 은 QoS 클래스에 따라 oom_score_adj 를 정한다.
IL-0071 작은 파일이 4만 개 넘게 든 단일 스테이지 이미지의 containerd 스냅샷이 쌓여 워커 노드의 inode 가 디스크보다 빠르게 소진되고 있었다Onkar Raghunath Shelke · 2026같은 원인 · 공통 kubelet
같은 원인 · 공통 kubelet
IL-0044 kube-prometheus-stack 업그레이드 뒤 Prometheus 가 WAL 재생 중 메모리를 50Gi 넘게 써서 시작할 때마다 OOMKilled 로 죽었다Saifeddine Rajhi · 2024같은 원인 · 공통 Prometheus
IL-0046 계획된 재시작 뒤 Prometheus 가 WAL 을 다 읽기 전에 startupProbe 에 걸려 재시작을 반복했고 지표가 빠졌다UK Ministry of Justice · 2024같은 원인 · 공통 Prometheus
IL-0169 FR-PAR 의 Scaleway Kubernetes API 가 메모리 부족으로 쓰러져 노드 인증이 막히고 Kapsule 노드가 NotReady 가 됐다.Scaleway · 2024같은 원인 · 공통 kubelet
https://incidentlib-mcp.benchlet.com/mcpAPI 는 키가 필요 없습니다. MCP 서버는 search_incidents, get_incident, list_incidents, get_topic, vocab 도구를 내놓습니다. 사용법은 API 와 MCP.
같은 원인 · 공통 Prometheus
같은 원인 · 공통 Prometheus
IL-0070 dask-gateway로 워커를 대량으로 띄우자 노드가 1분 만에 100대 늘었고, Prometheus가 메모리를 거의 다 쓰던 코어 노드에서 hub 파드를 비롯한 중요한 파드들이 축출되거나 재시작됐다2i2c · 2023같은 원인 · 공통 Prometheus
IL-0002 빌더 파드가 노드 한 대에 몰리자 kubelet 이 기본 API QPS 한도에 막혀 파드 상태를 늦게 갱신했고, CI 빌드가 AWS IAM 자격 증명을 받지 못해 실패했다Zalando · 2019같은 원인 · 공통 kubelet