본문 바로가기
소프트웨어개발

Kubernetes OOMKilled 해결: 메모리 limit·request·노드 압박 점검 순서

by 아빠띠띠뽀 2026. 9. 30.

Kubernetes 컨테이너 메모리 사용량과 OOMKilled 원인 점검 흐름을 나타낸 일러스트
AI로 직접 제작한 개념 일러스트입니다. 컨테이너 한도, 요청량, 노드 압박을 순서대로 확인하는 방법을 나타냅니다.

Kubernetes Pod가 반복 재시작되고 상태에 OOMKilled가 보인다면 먼저 '어느 컨테이너가 언제 왜 종료됐는지'를 확인하세요. 메모리 한도를 바로 올리면 잠시 안정될 수 있지만 누수, 동시 요청 증가, 메모리 기반 임시 볼륨 사용 같은 원인을 놓칠 수 있습니다. 이 글은 읽기 전용 명령으로 증거를 모으고, 애플리케이션 사용량과 클러스터 용량을 함께 고려해 수정하는 순서를 설명합니다.

1. 종료 원인을 먼저 확정하세요

Pod 이름·네임스페이스·컨테이너 이름을 실제 값으로 바꿔 다음 명령을 실행합니다. describe의 Last State, Reason, Exit Code, Events를 읽고 이전 컨테이너 로그를 보관하세요. 여러 컨테이너가 있는 Pod라면 문제가 난 컨테이너를 정확히 지정해야 합니다.

kubectl describe pod POD_NAME -n NAMESPACE
kubectl get pod POD_NAME -n NAMESPACE -o json
kubectl logs POD_NAME -n NAMESPACE -c CONTAINER_NAME --previous

재시작 직후 --previous는 이전 인스턴스 로그를 보는 데 유용하지만 로그 보존 환경에 따라 이미 사라졌을 수도 있습니다. Kubernetes의 실행 중인 Pod 디버깅 문서도 이전 컨테이너 로그 확인법을 안내합니다. Exit Code 137만 보고 메모리 초과라고 확정하지 마세요. SIGKILL로 종료됐다는 단서이며 종료 사유와 노드 이벤트를 함께 봐야 합니다.

2. request, limit, 노드 메모리는 서로 다릅니다

request는 스케줄링에서 필요한 용량을 표현하고 limit은 컨테이너가 사용할 수 있는 메모리 상한입니다. 컨테이너의 사용량이 limit을 넘으면 커널의 OOM 처리로 종료될 수 있습니다. 한편 노드 자체가 메모리 압박을 받으면 퇴거(Evicted)나 노드 수준 OOM이 발생할 수 있어 같은 대응을 적용하면 안 됩니다. 공식 리소스 관리 문서에서 request와 limit의 적용 방식을 확인할 수 있습니다.

메모리 단위도 점검하세요. 512Mi는 이진 단위이고 512M은 십진 단위입니다. 대소문자가 다른 m은 밀리바이트를 뜻해 의도와 전혀 다른 설정이 될 수 있습니다. 컨테이너별 제한을 확인하고 사이드카가 있는 경우 각 컨테이너를 따로 조사합니다.

3. 증거별로 원인 범위를 좁히는 표

관찰한 증거 먼저 확인할 것 다음 행동
Last State: OOMKilled 해당 컨테이너 limit·이전 로그·메모리 추이 피크 사용량과 제한값의 관계 분석
Pod가 Evicted로 종료 노드 MemoryPressure·이벤트·다른 Pod 노드 용량과 request, 퇴거 원인 확인
재시작이 특정 요청에서만 발생 파일 크기·동시 요청·버퍼·힙 설정 재현 부하로 메모리 급증 지점 찾기
평시에도 사용량이 계속 상승 캐시 상한·객체 보유·네이티브 메모리 프로파일링과 누수 의심 경로 추적
메트릭은 낮은데 OOM 발생 수집 간격·순간 피크·컨테이너 구분 더 촘촘한 관측과 종료 시점 로그 확인

이 표는 진단 순서를 위한 것이며 OOMKilled와 노드 압박이 항상 하나의 원인으로만 발생한다는 뜻은 아닙니다. 노드가 메모리 압박 상태라면 노드 압박 퇴거 문서의 신호도 살펴보세요.

4. 현재 사용량과 과거 피크를 분리하세요

kubectl top pod POD_NAME -n NAMESPACE --containers
kubectl top node
kubectl get events -n NAMESPACE --sort-by=.lastTimestamp

kubectl top은 Metrics Server가 설치돼 있어야 동작하며 최근 자원 사용량의 빠른 확인에 적합합니다. 종료 직전의 짧은 메모리 피크까지 보장하지는 않습니다. 공식 kubectl top 설명도 오토스케일링에 맞춘 관측값이며 고정밀 장기 분석을 대신하지 않는다고 안내합니다. 가능하다면 시계열 모니터링에서 재시작 직전의 컨테이너별 작업 집합과 요청량을 함께 비교하세요.

Pod가 CrashLoopBackOff도 보인다면 이는 반복 재시작의 결과 상태일 수 있습니다. 이전 로그, 종료 코드와 프로브를 함께 확인하는 방법은 기존 CrashLoopBackOff 점검 글에 정리했습니다.

5. 수정은 증거에 맞게 한 가지씩 하세요

정상 부하에서 메모리 한도만 지나치게 낮다면 측정한 피크와 여유를 근거로 limit을 조정하고 노드가 그 용량을 감당할 수 있는지 확인합니다. JVM·Node.js 등 런타임의 힙 상한만 볼 것이 아니라 네이티브 메모리, 파일 캐시, 사이드카와 메모리 기반 emptyDir 사용도 확인하세요. 트래픽 증가가 원인이라면 동시 처리 수와 Pod 복제 수의 관계도 검토합니다. 단순히 복제 수를 늘려도 각 Pod가 동일 요청에서 한도를 넘으면 문제는 반복됩니다.

변경 후에는 같은 입력과 피크 부하로 재현해 재시작 횟수, 응답 시간, 노드 메모리 여유를 기록합니다. 제한값을 무제한으로 만드는 조치는 노드 전체 장애 범위를 키울 수 있으므로 운영 환경에서는 피하세요.

6. 자주 묻는 질문

OOMKilled와 Evicted는 같은가요? 아닙니다. 컨테이너의 종료 사유와 노드 압박에 따른 Pod 퇴거는 구분해 조사해야 합니다.

메모리 request만 높이면 해결되나요? request는 주로 배치에 영향을 줍니다. limit 초과 또는 애플리케이션 급증을 그대로 두면 재시작은 계속될 수 있습니다.

Exit Code 137이면 무조건 OOM인가요? 137은 SIGKILL 종료를 시사하지만 원인을 단정할 수 없습니다. Last State와 이벤트, 노드 상태를 확인하세요.

자료 확인: 2026년 9월 30일. 클러스터 버전과 런타임에 따라 보이는 이벤트가 다를 수 있습니다.