Kubernetes 노드 OOM으로 인한 서비스 셧다운: 엔터프라이즈 복구 전략
문제 정의 — 노드 OOM이 서비스 가용성에 미치는 영향
커널의 OOM-killer는 노드의 전체 메모리가 고갈될 때 oom_score를 기준으로 프로세스를 강제로 종료한다. 쿠버네티스 환경에서는 kubelet이 자원 압박을 감지하면 컨테이너 프로세스를 종료하거나 QoS 및 eviction 정책에 따라 파드를 퇴출시킨다. 단일 프로세스의 종료는 서비스 인스턴스 감소, 세션 손실, 리더 교체를 초래할 수 있다. 이어지는 재스케줄링 지연과 이미지 풀·로그 쓰기 경쟁은 I/O 병목을 유발한다. 실무 체크: 먼저 문제 노드의 oom 관련 로그와 컨테이너 재시작 사유(oom_score, eviction reason)를 수집하고, 재스케줄링 시 트래픽을 단계적으로 분산해 동시 재시작 충돌을 완화하라. Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략을 수립할 때 이들 영향을 우선 고려해야 한다.
- 리더·스테이트풀 장애: 리더 선출 지연이 전체 처리 지연으로 이어진다
- 동시 재시작(Thundering Herd): 많은 파드가 동시에 기동하면 API 서버와 스케줄러에 큰 부하가 걸린다
- 스케줄링·노드 압박 전이: Eviction으로 부하가 다른 노드로 전이되며 연쇄 OOM이 발생할 수 있다
- 운영 영향: 모니터링과 알람이 폭주하고 롤백이나 수동 개입이 잦아진다
원인 진단과 탐지 방법
먼저 dmesg와 syslog에서 "Out of memory" 또는 oom_reaper/oom_kill 관련 로그를 찾아 커널 수준의 셧다운 시점을 파악한다. 이어서 kubelet 이벤트(예: kubectl describe node 또는 pod의 Events)에서 어떤 파드가 순차적으로 종료되었는지, eviction이나 Killed 메시지가 발생했는지 확인한다.
- cAdvisor/Node 메트릭(Prometheus): node_memory_MemAvailable, node_memory_MemTotal, container_memory_usage_bytes, container_memory_working_set_bytes, node_oom_events, kube_pod_container_status_restarts 등을 통해 메모리 추세와 스파이크를 파악한다.
- OOMScore 분석: /proc/[pid]/oom_score와 oom_score_adj를 확인하고, 컨테이너의 QoS(Guaranteed/Burstable/BestEffort) 및 리소스 요청·제한과 대조해 어떤 프로세스가 우선적으로 종료되었는지 평가한다.
진단 팁: 로그와 메트릭의 타임스탬프를 상호 비교해 원인 프로세스를 찾아내고, 메모리 누수인지 일시적 폭증인지 구분하라. 초기 탐지 흐름은 커널 로그 → kubelet 이벤트 → cAdvisor 지표 → OOMScore 순으로 설정하는 것이 효율적이다. 간단 체크리스트: 1) 커널 로그에서 OOM 시점 확인, 2) kubelet 이벤트로 영향을 받은 파드 파악, 3) 메트릭으로 메모리 경향 점검, 4) oom_score로 우선순위 검증. 운영 환경에서는 이 절차를 자동화해 알림과 포스트모템 데이터를 연결하면 복구 속도와 원인 규명 정확도가 높아진다. 또한 Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략 관련 가이드를 참고하면 정책 수립에 도움이 된다.
즉시 대응 런북 — 서비스 가용성 확보를 위한 단계별 조치
우선순위는 고객 트래픽 보호 → 복구 우선 스케줄링 → 노드 복구·교체 → 필요 시 롤백이다. 아래 절차를 상황에 맞게 신속히 수행한다. (Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략 관점에서 요약함)
- 노드 격리
- 문제 노드를 cordon(예: kubectl cordon <node>)해 신규 파드가 스케줄되지 않도록 한다
- 중요 서비스는 PDB를 확인한 뒤 drain(예: kubectl drain <node> --ignore-daemonsets --delete-local-data)으로 안전하게 이전한다
- 긴급 재스케줄·레플리카 증설
- 핫스팟 서비스부터 우선적으로 레플리카 수를 늘려 트래픽을 분산한다(Deployment/ReplicaSet 수평확장)
- 스케줄링 가능한 노드로 즉시 배치되도록 리소스 요청·제한을 일시 완화한다
- 노드 복구·교체
- 노드 로그(journalctl, dmesg)로 OOM 원인을 조사한 뒤 kubelet 재시작 또는 재부팅을 시도한다
- 하드웨어나 VM 문제라면 노드를 교체한다(provision → kubeadm join 또는 클라우드 인스턴스 교체)
- 롤백·검증
- 새로운 배포가 원인이라면 이전의 안정 버전으로 롤백하거나 레플리카 수를 줄인다
- 헬스체크·메트릭·사용자 트래픽을 모니터링해 정상화 여부를 확인한다
각 단계마다 책임자를 지정하고 변경 내용을 기록한다. 서비스 영향을 최소화하는 우선순위로 실행하되, 실무 체크리스트 예시(문제 인지 → cordon → 레플리카 증설 → 로그 확인 → 노드 교체 → 롤백 필요 시 실행)를 참고하면 대응 속도를 높일 수 있다.
자동 복구 설계 — 인프라와 컨트롤러 수준의 방어선
노드 OOM이 발생하면 인프라 레벨의 자동 치환과 쿠버네티스 컨트롤러 설정이 함께 작동해야 합니다. Cluster Autoscaler를 통해 리소스 부족 시 자동으로 스케일업·스케일아웃을 허용하고, 인스턴스 그룹(MIG/ASG)의 헬스체크로 비정상 노드를 감지해 자동 종료·교체하도록 구성하세요. 노드 교체 과정에서는 GKE의 node auto-repair 같은 자동 복구 기능을 활용하거나 Node Termination Handler로 안전하게 cordon과 drain을 트리거하면 됩니다. 이런 구성은 Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략의 핵심입니다.
- kubelet eviction: evictionHard·evictionSoft에 memory.available·nodefs를 설정하고, 적절한 grace period로 선제적 퇴출을 유도
- PodDisruptionBudget 연계: 서비스별 PDB를 설계해 evict API가 PDB를 존중하도록 하고, 최소 가용(minAvailable)은 현실적인 값으로 설정
- 운영 팁: CA와 헬스체크의 TTL·threshold를 조율해 불필요한 재시작을 줄이고, ready/healthz/metrics 같은 상태 수집으로 자동화 트리거를 보완. 간단 체크리스트 — 헬스체크 주기(예: 30s), 재시도 횟수(예: 3회), drain 전 파드 재배치 확인
예방적 조치 — 메모리 관리와 애플리케이션 레벨 튜닝
노드 OOM을 방지하려면 쿠버네티스의 리소스 설계와 런타임 메모리 제어를 함께 적용해야 합니다. 아래 항목을 점검해 실환경에 맞게 조정하십시오. (Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략과도 연계해 검토하세요.)
- 리소스 요청/제한·QoS 설계: request는 실제 워킹셋을 반영해 설정하고, limit은 과도한 확장을 억제하도록 약간의 여유를 둡니다. 핵심 서비스에는 Guaranteed(QoS: 요청=제한)를 고려하세요.
- limitRange·네임스페이스 정책: limitRange로 네임스페이스 단위의 기본 request/limit을 강제해 BestEffort 과잉 할당을 막습니다. PriorityClass로 중요 파드에 우선순위를 부여하세요.
- JVM/언어별 옵션: JVM은 컨테이너 지원을 활성화(-XX:+UseContainerSupport)한 뒤 -Xmx를 컨테이너 limit에 맞춰 설정하거나 -XX:MaxRAMPercentage를 사용합니다. Go는 GOMEMLIMIT, Node.js는 --max-old-space-size, Python은 프로파일링에 기반한 힙·스택 설정으로 네이티브 메모리를 제어하세요.
- OOMScoreAdj·쿠버네티스 설정: 가능한 환경에서는 프로세스의 oom_score_adj를 조정해 종료 우선순위를 관리합니다. 또한 kubelet의 evictionHard·evictionSoft 임계값을 현실적인 수준으로 설정해 과도한 추방을 방지하세요.
- 운영 관행: 정기적인 메모리 프로파일링, 리트라이와 백오프 구현, 적절한 모니터링 알람을 구성합니다. 자동 스케일과 리소스 패치 파이프라인을 마련해 재발을 줄이세요. 체크리스트 예: 프로파일링 → 알람 구성 → eviction 임계치 검토 → 자동 패치 순으로 우선 점검합니다.
관찰성·테스트·사후관리로 복구 역량 강화하기
적절한 알람과 대시보드는 초기 대응 속도를 좌우한다. node_memory_MemAvailable_bytes, container_memory_working_set_bytes, kube_node_status_allocatable_memory_bytes, kube_pod_container_status_terminated_reason(oomkilled) 같은 지표를 바탕으로 '단위 시간당 OOMKill 급증' 또는 '노드 사용율 ≥ 90% 지속' 같은 임계값 알람을 설정하고, 노드별 히트맵과 이벤트 타임라인을 구축하라. 로그(oom_reaper, dmesg)와 연계해 원인 연쇄를 시각화하면 근본 원인 파악이 빨라진다. 이는 Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략의 핵심 요소이기도 하다.
- 혼란·장애 주입: Chaos Mesh나 Litmus 같은 도구로 통제된 메모리 폭주·노드 OOM 실험을 주기적으로 실행해 런북과 자동화가 실제 상황에서 제대로 작동하는지 확인한다.
- 런북 검증: cordon·drain, kubelet 재시작, 노드 리부팅, 워크로드 자동 스케일링 절차를 스크립트화하고 실습해 RTO를 측정·단축한다. 반복 훈련이 효과적이다.
- 포스트모템: 블레임리스한 접근으로 발생 시간·증상·근본 원인·조치·소유자를 기록하고, 이를 추적 가능한 개선 항목으로 전환해 MTTR을 지속적으로 낮춘다. (실무 체크리스트 예: 발생 시각 → 영향 범위 → 관련 로그 스니펫 → 응급조치 → 후속 담당자 지정)
경험에서 배운 점
노드 OOM으로 서비스가 내려갈 때 현장에서 반복되는 실수는 문제를 단순히 '임시 재시작'으로 마무리하고 근본 원인을 살피지 않는 것입니다. 즉시 복구(노드 격리·drain·파드 재스케줄)는 필수이나, 같은 스케줄과 설정으로 다시 배포하면 문제가 재발합니다. 실무에서 효과를 본 순서는 다음과 같습니다. 먼저 빠르게 노드를 격리해 서비스 영향을 최소화하고, 그다음 커널·kubelet 관련 로그(dmesg, journalctl, kubelet 이벤트 등)를 확인합니다. 이어서 파드의 자원 요청/한계와 QoS·우선순위 불일치를 교정하고, 마지막으로 노드 예약(reserved)과 eviction 설정을 점검합니다.
아래는 Kubernetes 노드 OOM 발생 시 서비스 셧다운 복구 전략과 재발 방지에 초점을 둔 일반화된 체크리스트입니다. 운영 팀의 표준 런북에 바로 넣을 수 있도록 간결하게 정리했습니다.
- 즉시 대응: 문제 노드 cordon → drain(필요 시 force). 필요하면 신규 노드나 오토스케일러로 용량을 확보한다. 노드 재부팅은 원인 확인 후 결정한다.
- 로그·증거 수집: dmesg, journalctl, kubelet·kube-apiserver 이벤트와 컨테이너 OOM(oom_kill) 로그를 수집해 보관한다. 타임스탬프와 노드 식별자 등 메타데이터도 함께 남긴다.
- kubelet 설정 점검: eviction threshold(memory.available 등), eviction grace period, node allocatable, kube-reserved·system-reserved을 명확히 설정해 시스템 프로세스를 보호한다.
- 파드 자원 관리: 모든 워크로드에 requests를 의무화하고, 중요 서비스는 Guaranteed QoS로 배치한다. PriorityClass로 핵심 서비스의 우선복구를 보장하자.
- 스케줄링 정책: nodeSelector/토폴로지와 taints/tolerations로 메모리 집약 워크로드를 분리한다. PodDisruptionBudget으로 가용성을 유지한다.
- 자동화 및 모니터링: 메모리 압박·OOM 이벤트에 대한 알람을 설정하고, 노드 리메디에이션(예: 자동 cordon/drain)을 자동화한다. HPA/VPA로 리소스 조정을 보완한다.
- 용량·테스트: 실제 메모리 사용량을 기반으로 오버커밋 한계를 설정한다. 부하 테스트로 OOM 시나리오를 검증하고, 노드 유형·사이징 정책을 재검토한다.
- 사후 분석·문서화: RCA(원인·영향·대응) 보고서를 작성하고, 요청/한계/eviction 등 설정 변경 기록을 남겨 재발 방지 작업을 팀 규정에 반영한다.
- 사례: 동일한 컨테이너 이미지로 재배포 시 OOM이 반복된 경우가 있었습니다. 원인은 requests 미설정으로 인한 과도한 메모리 사용이었고, requests 명시와 소규모 부하 테스트로 문제를 해결했습니다.
댓글
댓글 쓰기