기본 콘텐츠로 건너뛰기

Kubernetes 노드 OOM 반복 발생 — 원인 분석과 실무적 방지책

Kubernetes 노드 OOM 반복 발생 — 원인 분석과 실무적 방지책

AI 생성 이미지: Kubernetes 노드 OOM 반복 발생 원인과 방지책
AI 생성 이미지: Kubernetes 노드 OOM 반복 발생 원인과 방지책

문제 정의 — 노드 OOM이 반복 발생하면 어떤 문제가 생기는가

노드 수준에서 OOM(Out Of Memory)이 반복되면 단순한 메모리 누수를 넘어 심각한 운영 리스크로 이어진다. 커널의 OOM killer가 작동하고, kubelet이 강제로 파드를 퇴거시키며 파드 재시작과 CrashLoopBackOff가 잦아진다. 이로 인해 서비스 가용성과 데이터 일관성이 즉시 악화된다. 이후 섹션에서는 Kubernetes 노드 OOM 반복 발생 원인과 방지책을 중심으로 해결 방안을 제시한다.

  • 증상: 커널 로그의 OOM 메시지, kubelet 이벤트의 "Evicted"/"OOMKilled" 기록, 파드 재스케줄링 빈도 상승, 노드의 NodeNotReady 상태 증가
  • 직접 영향: 인메모리 캐시나 세션 등 임시 상태 손실로 데이터 일관성이 흔들리고, 그 결과 요청 실패와 응답 지연이 늘어난다.
  • 운영 영향: 스케줄링 혼잡과 리소스 파편화가 발생한다. HPA나 클러스터 오토스케일러가 의도와 다르게 동작할 수 있고, 모니터링·알람의 폭주로 관제 피로가 커진다.
  • 성능 영향: 가비지 컬렉션과(스왑 사용 시) 스왑 활동 증가로 I/O 대기와 전체 서비스 레이턴시가 악화된다. 실무 체크리스트: 파드별 메모리 요청·한계 확인, 노드별 OOM 발생률 수집 및 추세 분석, 문제 재현 시 메모리 프로파일링 우선 수행

OOM 내부 메커니즘 — Linux OOM killer와 K8s Eviction의 차이

Linux 커널의 OOM killer는 시스템 전체 메모리와 스왑이 고갈될 때 커널이 프로세스를 강제 종료해 시스템을 구하는 마지막 수단입니다. 선택 기준은 프로세스의 메모리 사용량, 우선순위 등 여러 휴리스틱을 따릅니다. kubelet과는 독립적으로 동작하므로 갑작스럽고 영향 범위가 넓게 나타납니다. 실무 체크리스트: 리소스 요청·limit을 설정하고 QoS 우선순위를 검토하며 노드 메모리와 스왑 사용을 지속적으로 모니터링하세요.

  • kubelet eviction: 노드의 cgroup 메모리 집계와 kubelet의 soft/hard 임계값을 기준으로, 우선순위에 따라 파드 단위로 선제적으로 종료하거나 스케일다운을 시도합니다. 이 방식은 더 예측 가능하고 우아하게 처리됩니다.
  • cgroup 메모리 회계: 컨테이너는 cgroup 단위로 메모리가 집계됩니다. Limit을 초과하면 해당 컨테이너 수준에서 OOM(또는 OOM 이벤트)이 발생할 수 있습니다. 다만 노드 전체 메모리가 고갈되면 커널 OOM이 먼저 개입합니다.
  • QoS 역할: Guaranteed > Burstable > BestEffort 순으로 보호받습니다. Eviction 정책은 QoS와 리소스 요청/limit을 토대로 피해 범위를 결정합니다. 이런 차이를 이해하는 것은 Kubernetes 노드 OOM 반복 발생 원인과 방지책을 마련하는 데 중요합니다.

반복 OOM을 유발하는 주요 원인들

  • 메모리 누수: 애플리케이션이나 사이드카의 점진적 메모리 누수가 결국 노드 OOM으로 이어집니다. 진단은 heap dump, pmap, top 등으로 프로파일링하고, 예방은 리소스 limits 설정, livenessProbe 기반 자동 재시작, 누수 테스트 자동화로 시행하세요.
  • 요청(requests)/한계(limits) 미설정: requests가 없으면 파드는 스케줄되지만 과도한 오버커밋이 발생할 수 있습니다. limits를 지정하지 않으면 일부 컨테이너가 노드 자원을 잠식하므로, 최소 requests와 현실적인 limits를 정책으로 적용해 QoS를 보장해야 합니다.
  • 버스티 워크로드: 배치 작업, 크론 잡, 동시성 급증 같은 버스티 워크로드는 순간적인 메모리 폭증을 초래합니다. 제어 수단으로는 큐잉이나 스로틀링 도입, HPA·VPA 조합 사용, 작업 분산 등이 효과적입니다.
  • 노드 설정(호스트 예약·스왑 등): hostReserved·kubeReserved 부족, swap 활성화, kubelet eviction 설정 부적절은 반복 OOM의 원인이 됩니다. 권장 조치는 swap 비활성화, 예약값과 eviction 임계치 점검·조정입니다. 간단 체크리스트: requests/limits 확인, livenessProbe 설정, swap 비활성화, 모니터링 경보 구성. 운영 문서로 "Kubernetes 노드 OOM 반복 발생 원인과 방지책"을 정리해 두면 현장 대응이 훨씬 수월해집니다.

현장에서 바로 적용할 수 있는 진단 체크리스트

  • kubectl로 노드/파드 상태 확인kubectl describe node NODENAME, kubectl describe pod POD -n NAMESPACE로 Allocatable, Conditions, Events(특히 OOMKilled/eviction)과 컨테이너 상태를 확인하세요. 이벤트 타임스탬프와 상태 변화를 함께 보며 문제가 언제 시작됐는지 파악합니다.
  • kubelet/데몬 로그journalctl -u kubelet --since "1h" 또는 /var/log/kubelet.log에서 "eviction", "memory", "OOM" 키워드를 검색해 관련 로그를 확보하세요. 필요하면 kube-proxy와 CRI 데몬 로그도 함께 점검합니다.
  • dmesg/커널 로그dmesg | grep -i oom로 OOM killer 메시지(프로세스명, PID, 메모리 상태, 타임스탬프)를 확보하고 이벤트 발생 시점과 연동해 분석하세요.
  • Prometheus 메트릭 체크 — node: node_memory_MemAvailable_bytes, node_memory_MemTotal_bytes; 컨테이너: container_memory_working_set_bytes, container_memory_cache를 확인합니다. 메모리 상승률(예: rate(container_memory_working_set_bytes[5m]))과 요청/한도를 비교해 과다 소비 여부를 판단하세요.
  • OOM 이벤트 수집/상관kubectl get events --all-namespaces --field-selector reason=OOMKilled로 파드 OOM 기록을 수집하고, dmesg/journal의 OOM 로그와 타임스탬프를 매칭합니다. 로그 수집(Fluentd/EFK, Loki)과 메트릭(node-exporter/cAdvisor)을 중앙화해 상관분석을 쉽게 만드세요.
  • 즉시 조치 포인트 — 문제 발생 시 관련 노드를 격리하고, 문제 파드의 로그와 이미지 정보를 즉시 확보하세요. 리소스 요청(requests)/한도(limits)를 재검토하고 kubelet eviction 임계값을 점검합니다. 예시 체크리스트: 1) 노드 격리, 2) 문제 파드 로그·이미지 백업, 3) 요청/한도 및 eviction 임계값 재검토. 이 절차는 Kubernetes 노드 OOM 반복 발생 원인과 방지책을 검증할 때 특히 유용합니다.

단기 완화책과 구성 변경으로의 전환 방법

노드에서 OOM이 반복 발생하면 가용성 확보를 최우선으로 하고, 근본 원인 수정은 단계적으로 진행하세요. 단기 조치로는 문제 파드만 재시작하거나 노드를 cordon/drain으로 격리해 영향 범위를 좁히고, 필요하면 임시로 스케일 인·아웃해 부하를 분산합니다. liveness probe로 빠른 재시작을 유도할 수 있지만, 반복 재시작은 근본 해법이 아니라는 점을 염두에 두세요. 운영 중에는 로그와 메트릭을 확인하고 재현 테스트를 병행해 변경 효과를 검증하는 것이 중요합니다. (참고: 본 지침은 Kubernetes 노드 OOM 반복 발생 원인과 방지책 적용 시 유용합니다.)

  • 임시: cordon/drain으로 노드를 격리하고 taint로 스케줄을 차단한 뒤, 영향 파드만 재시작하거나 스케일링해 즉시 가용성을 확보합니다.
  • 중간: 문제 파드의 requests와 limits를 점검하세요 — 특히 memory limit을 명시해 QoS를 확보합니다.
  • 중요: eviction 및 kubelet 설정을 확인하고 evictionHard(memory.available) 값을 실제 워크로드에 맞게 조정합니다.
  • QoS 전략: 메모리 안정성이 최우선이면 requests=limits로 Guaranteed를 사용하고, 그렇지 않다면 Burstable을 선택하세요. BestEffort는 가능하면 피합니다.
  • 전환 절차: 임시 조치로 서비스 안정화 → 매니페스트(리소스 요청·제한, LimitRange, ResourceQuota) 수정 → 소규모 Canary 적용 → 클러스터 전반의 eviction 및 kube-reserved 튜닝. 실무 체크리스트 예: 1) 메모리 요청/제한 설정 확인 2) LimitRange/ResourceQuota 적용 여부 검증 3) Canary로 영향 관찰 4) eviction 정책과 kubelet 예약 값 확인.

메모리 스파이크와 OOM kill 이벤트를 지속적으로 모니터링하고, 재현 테스트를 통해 구성 변경이 기대한 대로 동작하는지 반드시 검증하세요.

장기적 방지책: 정책·자동화·운영 관행 정착

Admission 단계부터 운영에 이르기까지 재발을 막기 위해 다음 항목을 체계적으로 적용한다.

  • Admission 정책: ResourceQuota, LimitRange, PodPriority/Preemption을 설정하고 OPA/Gatekeeper 규칙으로 리소스 요청·제한 누락을 차단한다.
  • CI·테스트: PR 파이프라인에서 리소스 어설션과 정적 분석(요청/limit 검사)을 수행하고, 부하·스트레스 테스트로 OOM 시나리오를 검증한다.
  • 모니터링·알림: node, kubelet, cAdvisor, Prometheus 등을 활용해 메모리 사용량과 RSS를 추적하고, 예측 임계치 기반 알림과 명확한 에스컬레이션 경로를 마련한다.
  • 자동화 대응: Cluster Autoscaler와 HPA/VPA 조합을 활용하고, 급증 시 자동 cordon/drain 또는 크레딧 기반 스케일링으로 부하를 완화한다.
  • 운영 관행: OOMKill 로그와 eviction 이벤트를 수집·분석하고 정기적인 용량 계획을 수행한다. 정책 배포는 GitOps로 관리하며, 서비스 소유자별 런북과 사후분석(RCA)을 의무화한다.
  • 실무 체크리스트(예): ① 모든 PR에 리소스 요청/limit 검증 포함, ② 핵심 노드에 80%·90% 임계치 알림 설정, ③ 분기별 부하 테스트와 용량 검토 회의 일정화 — 우선순위는 Kubernetes 노드 OOM 반복 발생 원인과 방지책 관점에서 정한다.

경험에서 배운 점

반복적인 Kubernetes 노드 OOM은 보통 단일 원인에서 발생하지 않습니다. 컨테이너 메모리 누수, 부적절한 requests/limits 설정, kubelet의 eviction 임계치 미설정, 노드 예약(systemReserved/kubeReserved) 부재, 그리고 클러스터 수준의 메모리 오버커밋이 복합적으로 작용하는 경우가 많습니다. 노드에서의 페이지캐시나 캐시 사용, 그리고 로그 수집기나 컨테이너 런타임 같은 호스트 프로세스의 메모리 요구를 간과하면 OOM 사태가 잦아집니다. 요약하면, Kubernetes 노드 OOM 반복 발생 원인과 방지책은 인프라·설정·애플리케이션 세 부분을 함께 검토해야 합니다.

실무적 방지 체크리스트: 컨테이너마다 현실적인 requests와 합리적 limits를 설정하고 네임스페이스별 LimitRange/ResourceQuota로 강제; kubelet에 systemReserved/kubeReserved와 evictionHard(예: memory.available)를 설정해 시스템 프로세스 보호; Prometheus + node-exporter / kube-state-metrics로 노드·파드 메모리 사용과 OOMKilled 이벤트를 모니터링하고 알람을 구성; Cluster/Node autoscaler 또는 VPA로 수요에 따른 용량 확보; 정기적인 부하 및 메모리 스트레스 테스트로 누수와 스파이크를 탐지; swap은 Kubernetes에서 권장되지 않으니 비활성화 유지; 중요한 파드에는 oom_score_adj 조정을 신중히 검토. 추가로 CI/CD 파이프라인에 메모리 소비 검증(스모크 테스트 포함)과 정기 요약 리포트를 자동화해 운영 가시성을 높이세요.

운영 실수와 단기 대응 팁: 흔한 실수는 requests를 지나치게 낮게 설정해 과도한 오버커밋을 허용하거나 limits 없이 배포하는 것입니다. 또한 OOM 발생 시 힙 덤프나 프로파일을 수집하지 않거나, 모든 시스템 파드를 소수의 노드에 몰아두는 실수가 잦습니다. 문제가 발생하면 즉시 해당 노드를 cordon 후 drain으로 격리하고, OOMKilled 이벤트·/var/log/kubelet·컨테이너 로그·프로세스별 메모리 프로파일을 신속히 수집해 메모리 누수, 스파이크, 부하 패턴 중 무엇이 원인인지 판별하세요. 후속 조치로는 포스트모템을 통해 리소스 설정, 스케일 정책, 모니터링 임계값을 갱신하고, 동일 원인이 재발할 경우 자동화된 노드 스케일업이나 리소스 재조정 루틴을 도입해 반복을 막으십시오.

AI 생성 이미지: Kubernetes 노드 OOM 반복 발생 원인과 방지책
AI 생성 이미지: Kubernetes 노드 OOM 반복 발생 원인과 방지책

댓글

이 블로그의 인기 게시물

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 (Request Parameter 전체보기)

Java Servlet Request Parameter 완전 정복 — GET/POST 모든 파라미터 확인 & 디버깅 예제 Java Servlet Request Parameter 완전 정복 웹 애플리케이션에서 클라이언트로부터 전달되는 Request Parameter 를 확인하는 것은 필수입니다. 이 글에서는 Java Servlet 과 JSP 에서 GET/POST 요청 파라미터를 전체 출력하고 디버깅하는 방법을 다양한 예제와 함께 소개합니다. 1. 기본 예제: getParameterNames() 사용 Enumeration<String> params = request.getParameterNames(); System.out.println("----------------------------"); while (params.hasMoreElements()){ String name = params.nextElement(); System.out.println(name + " : " + request.getParameter(name)); } System.out.println("----------------------------"); 위 코드는 요청에 포함된 모든 파라미터 이름과 값을 출력하는 기본 방법입니다. 2. HTML Form과 연동 예제 <form action="CheckParamsServlet" method="post"> 이름: <input type="text" name="username"><br> 이메일: <input type="email" name="email"><b...

PostgreSQL 달력(일별,월별)

SQL 팁: GENERATE_SERIES로 일별, 월별 날짜 목록 만들기 SQL 팁: GENERATE_SERIES 로 일별, 월별 날짜 목록 만들기 데이터베이스에서 통계 리포트를 작성하거나 비어있는 날짜 데이터를 채워야 할 때, 특정 기간의 날짜 목록이 필요할 수 있습니다. PostgreSQL과 같은 데이터베이스에서는 GENERATE_SERIES 함수를 사용하여 이 작업을 매우 간단하게 처리할 수 있습니다. 1. 🗓️ 일별 날짜 목록 생성하기 2020년 1월 1일부터 12월 31일까지의 모든 날짜를 '1 day' 간격으로 생성하는 쿼리입니다. WITH date_series AS ( SELECT DATE(GENERATE_SERIES( TO_DATE('2020-01-01', 'YYYY-MM-DD'), TO_DATE('2020-12-31', 'YYYY-MM-DD'), '1 day' )) AS DATE ) SELECT DATE FROM date_series 이 쿼리는 WITH 절(CTE)을 사용하여 date_series 라는 임시 테이블을 만들고, GENERATE_SERIES 함수로 날짜를 채웁니다. 결과 (일별 출력) 2. 📅 월별 날짜 목록 생성하기 동일한 원리로, 간격을 '1 MONTH' 로 변경하면 월별 목록을 생성할 수 있습니다. TO...

CSS로 레이어 팝업 화면 가운데 정렬하는 방법 (top·left·transform 완전 정리)

레이어 팝업 센터 정렬, 이 코드만 알면 끝 (CSS 예제 포함) 이벤트 배너나 공지사항을 띄울 때 레이어 팝업(center 정렬) 을 깔끔하게 잡는 게 생각보다 어렵습니다. 화면 크기가 변해도 가운데에 고정되고, 모바일에서도 자연스럽게 보이게 하려면 position , top , left , transform 을 정확하게 이해해야 합니다. 이 글에서는 아래 내용을 예제로 정리합니다. 레이어 팝업(center 정렬)의 기본 개념 자주 사용하는 position: absolute / fixed 정렬 방식 질문에서 주신 스타일 top: 3.25%; left: 50%; transform: translateX(-50%) 의 의미 실무에서 바로 쓰는 반응형 레이어 팝업 HTML/CSS 예제 1. 레이어 팝업(center 정렬)이란? 레이어 팝업(레이어 팝업창) 은 새 창을 띄우는 것이 아니라, 현재 페이지 위에 div 레이어를 띄워서 공지사항, 광고, 이벤트 등을 보여주는 방식을 말합니다. 검색엔진(SEO) 입장에서도 같은 페이지 안에 HTML이 존재 하기 때문에 팝업 안의 텍스트도 정상적으로 인덱싱될 수 있습니다. 즉, “레이어 팝업 센터 정렬”, “레이어 팝업 만드는 방법”과 같이 관련 키워드를 적절히 넣어주면 검색 노출에 도움이 됩니다. 2. 질문에서 주신 레이어 팝업 스타일 분석 질문에서 주신 스타일은 다음과 같습니다. <div class="layer-popup" style="width:1210px; z-index:9001; position:absolute; top:3.25%; left:50%; transform:translateX(-50%);"> 레이어 팝업 내용 <...