Hunny's Daily

개발과 일상에서의 달콤한 순간들을 기록하며, 유용한 팁과 인사이트를 공유합니다.

OOMKill은 왜 발생하는가

Pod가 갑자기 종료되는 진짜 이유

Kubernetes 환경에서 운영하다 보면 Pod가 갑자기 종료되고 다시 생성되는 상황을 자주 마주하게 된다. 로그를 확인해 보면 원인으로 OOMKill 이 표시되는 경우가 많다. 이 현상을 정확히 이해하지 못하면 Scale Out을 해도 동일한 문제가 반복된다. 이 글에서는 OOMKill이 발생하는 이유와 Kubernetes에서의 동작 원리를 개념 중심으로 정리한다.


OOMKill이란 무엇인가

OOMKill은 Out Of Memory Kill의 약자다.
컨테이너가 사용할 수 있는 메모리 한도를 초과했을 때, Kubernetes가 해당 Pod를 강제로 종료하는 현상을 의미한다.

중요한 점은 다음이다.

  • 애플리케이션이 직접 종료한 것이 아님
  • Kubernetes가 노드를 보호하기 위해 강제 종료

즉, OOMKill은 시스템 보호 메커니즘이다.


OOMKill은 언제 발생하는가

OOMKill은 다음 조건이 동시에 충족될 때 발생한다.

  • Pod에 메모리 limits가 설정되어 있음
  • 애플리케이션이 limits를 초과하는 메모리를 사용
  • 메모리 회수가 불가능한 상태

이 순간 Kubernetes는 Pod를 즉시 종료한다.


메모리 limits를 초과하면 바로 종료되는 이유

CPU와 달리 메모리는 초과 사용을 허용하지 않는다.

  • CPU
    • limits 초과 시 사용량 제한
    • Pod는 계속 실행
  • 메모리
    • limits 초과 시 즉시 종료
    • OOMKill 발생

메모리는 노드 전체 안정성에 직접적인 영향을 주기 때문이다.


OOMKill이 발생했을 때 내부 동작

OOMKill이 발생하면 Kubernetes는 다음 순서로 동작한다.

  1. Pod 메모리 사용량이 limits 초과
  2. 커널 OOM Killer 실행
  3. 해당 컨테이너 강제 종료
  4. Pod 상태 OOMKilled 기록
  5. ReplicaSet이 새 Pod 생성

이로 인해 Pod는 재시작되지만, 근본 원인이 해결되지 않으면 동일한 문제가 반복된다.


OOMKill이 반복되면 생기는 문제

OOMKill이 반복되면 다음 현상이 나타난다.

  • Pod 재시작 루프 발생
  • 트래픽 처리 불안정
  • 응답 지연 또는 오류 증가

Scale Out을 해도 각 Pod가 동일한 메모리 한계를 가지면 문제는 해결되지 않는다.


OOMKill과 Scale Out의 관계

Scale Out은 Pod 수를 늘리는 전략이다.
그러나 OOMKill은 Pod 하나의 메모리 문제다.

다음과 같은 경우 Scale Out은 도움이 되지 않는다.

  • 각 Pod가 동일한 메모리 부족 상태
  • 초기화 시 메모리 급증
  • 특정 요청에서 메모리 폭증

이 경우 Pod 수를 늘려도 각 Pod는 동일하게 종료된다.


Spring Boot / JVM 애플리케이션에서 OOMKill이 잦은 이유

JVM 기반 애플리케이션은 메모리 사용 특성이 뚜렷하다.

  • 힙 메모리 외 추가 메모리 사용
  • GC 타이밍에 따라 사용량 변동
  • 컨테이너 메모리 한계 인식 문제

이로 인해 JVM이 컨테이너 limits를 초과해 메모리를 사용하고 OOMKill이 발생하는 경우가 많다.


메모리 leaks와 OOMKill의 차이

OOMKill은 반드시 메모리 누수 때문만은 아니다.

  • 메모리 누수
    • 점진적 증가
    • 장시간 후 발생
  • 설정 문제
    • 트래픽 급증 시 즉시 발생
    • 특정 요청에서 재현 가능

원인을 구분하지 않으면 잘못된 대응을 하게 된다.


OOMKill을 줄이기 위한 기본 접근

OOMKill을 줄이기 위해 다음을 점검해야 한다.

  • 메모리 limits 설정값
  • 실제 애플리케이션 사용량
  • 트래픽 피크 시 사용 패턴
  • 초기 기동 시 메모리 사용량

무작정 limits를 올리는 것은 근본 해결책이 아니다.


requests / limits 설정과 OOMKill

limits는 보호 장치이지만, 너무 낮으면 OOMKill이 빈번해진다.

일반적인 접근은 다음과 같다.

  • requests는 평균 사용량 기준
  • limits는 피크 사용량 기준
  • 충분한 여유 확보

requests와 limits는 함께 조정되어야 한다.


OOMKill 발생 시 확인 순서

OOMKill이 발생하면 다음 순서로 확인하는 것이 일반적이다.

  1. Pod 상태 및 종료 사유 확인
  2. 메모리 사용량 추이 확인
  3. limits 설정값 확인
  4. 특정 요청 또는 시점 분석
  5. 애플리케이션 메모리 구조 점검

순서를 지키면 원인 파악이 쉬워진다.


언제 OOMKill이 가장 위험한가

다음 상황에서 OOMKill은 특히 위험하다.

  • 트래픽 피크 시간
  • 배포 직후
  • Scale Out 직후

이 시점은 서비스 영향도가 가장 크다.


정리

OOMKill은 Kubernetes가 노드를 보호하기 위해 Pod를 강제로 종료하는 메커니즘이다. 메모리 limits를 초과하면 즉시 발생하며, Scale Out만으로는 해결되지 않는다. OOMKill을 줄이기 위해서는 애플리케이션의 메모리 사용 특성과 requests / limits 설정을 함께 이해해야 한다. Kubernetes 운영에서 OOMKill은 반드시 이해하고 관리해야 할 핵심 개념이다.