Kubernetes
Pod의 OOMKilled 문제 원인 분석 및 해결 방법
hdoo
2025. 3. 3. 08:00
Kubernetes 환경에서 Pod가 갑작스럽게 종료되며 OOMKilled 상태가 되는 경우, 운영자 입장에서는 당황할 수밖에 없습니다. 이는 단순한 에러 로그가 아니라, 리소스 설정 미스 혹은 애플리케이션의 과도한 메모리 사용이 불러온 중요한 징후입니다.
이 글에서는 OOMKilled의 발생 원리부터, 원인 분석, 그리고 재발 방지를 위한 설정 팁까지 다뤄보겠습니다.
OOMKilled란 무엇인가?
OOMKilled는 Out Of Memory Killed의 약자로, 컨테이너가 할당받은 메모리 한도(memory limit)를 초과하여 종료된 상태를 의미합니다.
Kubernetes는 컨테이너 실행 시 설정한 memory limit 값보다 메모리를 더 사용하면, cgroup 제한에 의해 커널이 해당 프로세스를 강제로 종료시킵니다. 이 때 Pod는 OOMKilled 상태로 기록됩니다.
kubectl get pod my-app-123 -o json | jq '.status.containerStatuses[].lastState.terminated'
{
"reason": "OOMKilled",
"exitCode": 137,
...
}
왜 OOMKilled가 발생할까?
- 리소스 제한 설정이 너무 낮은 경우
- 개발 환경에서 무심코 설정한 낮은 limit 값이 실제 서비스 상황에서 부족해짐
- 메모리 누수(Memory Leak)
- 애플리케이션의 메모리 해제가 정상적으로 이뤄지지 않아 사용량이 지속 증가
- 버스트 트래픽/비정상 입력
- 특정 입력이나 이벤트로 인해 일시적으로 과도한 메모리 소비 발생
- Limit 설정은 했지만 Request는 안 한 경우
- CPU는 공유되지만, 메모리는 강제 제한됨 → 예상보다 적은 메모리로 실행됨
- JVM 기반 앱의 heap 설정 누락
- Java 앱에서 -Xmx 없이 실행하면, 전체 메모리를 heap으로 쓰려고 시도
OOMKilled 문제 진단 방법
1. Pod 상태 확인
kubectl describe pod <pod-name>
- 이벤트 로그에서 OOMKilled 여부 확인
2. 리소스 사용량 확인
- 모니터링 도구 활용 -> Prometheus/Grafana 등을 활용
kubectl top pod <pod-name>
- 리소스 peak 시점 기록 여부 확인
3. 로그 및 내부 상태 분석
- 애플리케이션 로그 확인 (메모리 누수 의심)
- 필요시 컨테이너 쉘 접속하여 ps, top 등으로 메모리 사용량 추적
해결 방법과 재발 방지 팁
1. 적절한 리소스 설정 (Request / Limit)
resources:
requests:
memory: "256Mi"
limits:
memory: "512Mi"
- 너무 작게 잡으면 잦은 OOM, 너무 크면 노드 낭비 → 실제 사용량 기반으로 조정
2. JVM 기반 앱이라면 heap 제한 필수
JAVA_OPTS="-Xms128m -Xmx256m"
- Container limit보다 JVM heap이 커지면 바로 OOM 발생
3. VPA (Vertical Pod Autoscaler) 도입 고려
- 애플리케이션의 메모리 사용량을 학습해 자동으로 Request/Limit을 조정
4. 메모리 누수 점검
- Go, Node.js, Java 등에서 누수 탐지 도구 활용 (e.g., pprof, heap dump)
5. 모니터링 설정
- 메모리 사용량에 대한 알람 설정
- OOMKilled 발생 시 자동 Slack/이메일 알림
정리
Pod의 OOMKilled는 단순 종료가 아니라 운영 환경이 감당하지 못하는 워크로드가 발생했음을 나타내는 신호입니다. 이는 곧 시스템의 신뢰성과 사용자 경험에 영향을 미칠 수 있기 때문에, 정확한 분석과 대응이 필수입니다.
리소스 설정, 모니터링, 애플리케이션의 메모리 효율 개선을 통해 운영환경에서 최적의 방법을 찾으시면 도움이 될 것이라고 생각합니다.