← 아티클 목록

OOMKilled 디버깅 — 컨테이너가 메모리로 죽을 때 (Exit 137)

2026-07-13#kubernetes#트러블슈팅#메모리

kubectl describe pod에서 Last State: Terminated, Reason: OOMKilled, Exit Code: 137을 봤다면, 컨테이너가 메모리 한도를 넘어 커널 OOM killer에 의해 강제 종료된 것입니다. 두 가지 경우를 구분해야 합니다: 내 컨테이너가 자기 limit을 넘었나, 아니면 노드 전체가 부족했나.

requests vs limits — 먼저 이해

설정의미
requests.memory스케줄링 보장치(이만큼은 확보)
limits.memory상한(넘으면 OOMKilled)

OOMKilled는 보통 컨테이너가 limits.memory를 초과했을 때 발생합니다. limit이 없으면 노드 메모리가 부족할 때 죽을 수 있습니다.

1단계 — 어느 쪽인지 확인

Kubernetes
kubectl describe pod <pod>     # Reason: OOMKilled, 컨테이너별 Last State
kubectl get events --field-selector reason=OOMKilling

컨테이너의 Last State가 OOMKilled면 그 컨테이너의 limit 문제. 노드 레벨 이벤트(The node was low on resource: memory)면 노드 압박.

2단계 — 실제 사용량 측정

추측으로 limit을 올리지 말고 실제 사용량을 봅니다.

Kubernetes
kubectl top pod <pod> --containers   # metrics-server 필요

피크 사용량을 알아야 limit을 합리적으로 잡습니다.

해결

① limit이 너무 낮음 — 실제 피크 + 여유(20~30%)로 limits.memory 상향.

② 메모리 누수 — limit을 올려도 시간이 지나면 또 죽음. 앱의 누수를 잡아야 함(힙 덤프·프로파일링). 임시로 limit 상향은 미봉책.

③ JVM 등 런타임 인식 문제 — 컨테이너 limit을 모르고 호스트 메모리 기준으로 힙을 잡는 경우. 최신 런타임은 cgroup 인식하지만, 옛 설정은 -XX:MaxRAMPercentage 등으로 명시.

④ requests만 있고 limit 없음 — 노드 압박 시 우선 종료 대상. 적절한 limit을 설정.

체크리스트

Kubernetes
kubectl describe pod <pod>            # OOMKilled가 컨테이너인지 노드인지
kubectl top pod <pod> --containers    # 실제 사용량
kubectl get pod <pod> -o jsonpath='{.spec.containers[*].resources}'  # 현재 requests/limits

requests/limits를 직접 설정하고 OOMKilled를 재현·해결하는 실습은 쿠버네티스 트랙에서 무료로 할 수 있습니다.