기본 콘텐츠로 건너뛰기

Kubernetes 노드 메모리 압박으로 인한 OOMKill 폭증 대응 가이드

Kubernetes 노드 메모리 압박으로 인한 OOMKill 폭증 대응 가이드

AI 생성 이미지: K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안
AI 생성 이미지: K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안

문제 정의 — 노드 메모리 압박과 OOMKill 폭증의 실제 양상

주로 특정 시점에 OOMKilled 로그가 대량으로 발생하고, 노드가 MemoryPressure 상태로 전환되며 파드가 연쇄적으로 재시작하는 형태가 관찰됩니다. 이와 동시에 kubelet의 eviction 이벤트, dmesg의 oom_reaper 메시지, 그리고 Swap·Available 메모리 지표의 급격한 감소가 동반됩니다.

  • 메모리 과다 사용: 애플리케이션이 예측보다 많은 메모리를 소비하여 노드 여유 자원을 소진합니다.
  • 부적절한 요청/한도: requests가 부족하거나 limits가 미설정되어 스케줄링과 리소스 제한이 제대로 작동하지 않습니다.
  • 메모리 누수: 장기간 운영 중 메모리 사용량이 점진적으로 증가하는 현상입니다.
  • 노드 과밀화/오버커밋: 파드가 한 노드에 과밀하게 배치되어 정상 여유 메모리가 빠르게 사라집니다.

비즈니스 영향으로는 서비스 가용성 저하, 응답 지연과 SLA 위반, 디버깅·재배포 비용 증가 및 알림 폭주로 인한 운영 부담 증가가 있습니다. 실무 체크리스트 예: OOMKilled 발생 시점의 노드 메모리 사용률, kubelet eviction 이벤트, dmesg의 oom_reaper 로그와 해당 파드의 requests/limits, 프로세스별 메모리(RSS)를 우선 확인하세요. 이후 섹션에서는 K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안에 대한 실무적 접근을 제시합니다.

관찰과 진단 — 어떤 지표와 로그로 원인을 빠르게 파악할까

문제 발생 시에는 교차검증할 핵심 항목들만 빠르게 확인한다.

  • 노드·파드 메모리 사용량: Prometheus(cAdvisor)의 node_memory_MemAvailable_bytes와 container_memory_working_set_bytes로 노드의 남은 메모리와 컨테이너의 실제 사용량을 파악한다.
  • kubelet 퇴출(eviction) 이벤트: kubectl describe node와 이벤트 로그에서 eviction 또는 "memory pressure" 메시지를 확인하고, kubelet의 evictionHard 설정도 점검한다.
  • dmesg(oom_killer): dmesg | grep -i oom 또는 journalctl -k로 커널 OOM 로그를 확보해 대상 PID와 oom_score를 확인한다.
  • cAdvisor·Prometheus 메트릭: container_spec_memory_limit_bytes, container_memory_cache_bytes, node_memory_SwapFree_bytes 등을 확인해 메모리 한계, 캐시, 스왑 상태를 점검한다.
  • 이벤트 타임라인 분석: kubectl get events --all-namespaces --sort-by=.metadata.creationTimestamp와 Grafana의 타임라인을 이용해 메모리 스파이크, eviction, OOM 로그의 타임스탬프를 정렬해 원인 연관성을 확인한다.

핵심은 그래프(메모리 사용) ↔ kubelet 이벤트(퇴출) ↔ 커널 OOM 로그(대상 프로세스)를 타임라인 상에서 교차검증하는 것이다. 이를 통해 요청/리미트 불일치, 스왑 사용, 또는 리소스 누수를 빠르게 좁혀 원인을 규명한다. 간단한 체크리스트: 메트릭(사용량 vs 리밋) 확인 → 최근 배포·롤아웃 여부 점검 → 노드의 스왑 활성화 확인 → 문제 컨테이너의 메모리 사용 패턴 검토. 이런 절차는 K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안에도 직접적으로 적용된다.

긴급 대응(단기) — OOMKill 폭증 발생 시 즉시 취해야 할 우선 조치 (K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안)

  • 노드 격리(cordon/drain) — 문제가 있는 노드를 신속히 격리하세요. 먼저 kubectl cordon NODE로 스케줄링을 차단한 뒤, 이전 가능한 파드는 아래 명령으로 안전하게 이동합니다: kubectl drain NODE --ignore-daemonsets --delete-local-data --force.
  • 저우선순 파드 축출·스케일아웃 — 우선순위·라벨을 기준으로 베스트이펙트나 저우선 파드를 먼저 축출하거나 Eviction API를 사용합니다. 필요하면 워커 풀을 수평 확장하여 부하를 분산하세요. 예: kubectl delete pod -l app=best-effort -n NAMESPACE 또는 kubectl scale deploy NAME --replicas=N.
  • kubelet eviction 임시 변경 — 매니지드 환경이 아닐 경우 노드의 kubelet 설정에서 evictionHardmemory.available 값을 상향(예: 200Mi)해 kubelet이 더 일찍 축출하도록 조정합니다. 변경 후에는 sudo systemctl restart kubelet로 재시작하세요. 매니지드 클러스터는 프로바이더 절차에 따르십시오.
  • 문제 프로세스 강제 종료(최후 수단) — SSH로 노드에 접속해 메모리 점유가 큰 프로세스를 확인합니다: ps aux --sort=-rss | head. 신중히 대상 프로세스를 선별하여 sudo kill -9 PID로 종료하세요. 노드 안정성에 큰 영향을 줄 수 있으니 매우 조심해야 합니다. 확인 절차(체크리스트): 영향 범위 확인 → 관련 로그 확보 → 대상만 종료 → 종료 후 상태·리소스 재확인.

리소스·스케줄링 정책 개선(중기) — 재발 방지를 위한 플랫폼 설계

노드 메모리 압박의 재발을 막기 위해 플랫폼 수준에서 리소스와 스케줄링 정책을 체계적으로 정비합니다. 특히 K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안 관점에서 우선순위를 정하고 일관되게 적용해야 합니다. 실무 체크리스트 예: 모든 파드에 request/limit 설정 여부 확인, 네임스페이스별 ResourceQuota 적용, VPA의 자동 리스타트 동작 검토.

  • 요청/한도 정비: 컨테이너별 request를 기본값으로 필수화하여 QoS를 확보합니다. Guaranteed 또는 Burstable 클래스를 유도하고 BestEffort는 배제합니다.
  • LimitRange·ResourceQuota: 네임스페이스 단위로 최소·최대 요청을 정의하고, 네임스페이스별 메모리 상한을 설정해 과다 배치를 차단합니다.
  • QoS 클래스 활용: request와 limit을 적절히 설정해 Eviction 우선순위를 제어합니다.
  • Pod Priority/Preemption: 핵심 서비스의 우선순위를 정의하고 예비 용량을 확보해 중요한 파드를 보호합니다.
  • HPA/VPA 조합: HPA는 레플리카 기반의 스케일아웃을 담당하고, VPA는 단일 파드의 리소스 권장치를 제공합니다. 단, VPA의 자동 리스타트 동작은 주의가 필요합니다.
  • 노드 풀 분리·taints: 메모리 집약 워크로드 전용 노드풀과 taint/toleration으로 혼잡을 격리합니다. Cluster Autoscaler와 headroom 정책을 함께 운영해 안정적인 용량 관리를 구현하세요.

노드·커널 튜닝과 인프라 최적화(중장기) — 메모리 관리 강화 방법

K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안 관점에서, 노드 수준에서 안정적으로 메모리를 관리하려면 cgroup 설정, 커널 파라미터, 디스크·이미지 정책을 함께 조정해야 한다. 주요 권장사항:
  • cgroup: 가능하면 cgroup v2와 메모리 컨트롤러를 사용하고, kubelet의 --system-reserved와 --kube-reserved로 노드 예약을 설정한다.
  • eviction: eviction-hard(예: memory.available<100Mi)와 eviction-soft/softGracePeriod로 퇴출 우선순위를 정하고, ephemeral-storage 임계값도 함께 설정한다.
  • swap/커널: 운영 환경에서는 swap 비활성(또는 vm.swappiness=0)을 권장하며, swap accounting을 활성화한다. vm.overcommit_memory=2와 vm.overcommit_ratio 조정으로 메모리 과다할당을 방지한다.
  • hugepages: 메모리 집중형 DB나 JVM 워크로드는 2MB/1GB hugepages를 예약해 TLB 오버헤드를 줄이고, Pod spec에서 hugepages 리소스를 선언한다.
  • 이미지·디스크 영향 최소화: imageGCHigh/Low와 imagePullPolicy를 조정하고, 슬림 이미지와 레이어 재사용을 권장한다. 노드 로컬 캐시와 로그 회전을 적용해 디스크 사용을 관리한다.
  • 인프라: 메모리 최적화 노드풀과 자동 스케일링을 도입하고, 노드 메모리와 oom_kills를 모니터링하며 변경을 단계적으로 롤아웃한다. (체크리스트 예: 변경 전 캔아리 노드에서 eviction/oom_kill 지표 확인 → 설정 적용 → 소수 노드로 확장 → 전체 롤아웃)

운영 체계화와 자동화 — 모니터링·알림·런북으로 지속적으로 관리하기

  • 알림 임계값 설계: node.memory.available, eviction_threshold, OOMKill 빈도에 대해 경고·심각 등 다단계 임계값을 설정합니다. 노드별 정상치(베이스라인)와 워크로드 패턴을 기준으로 동적 임계값을 적용하세요. 관련 메트릭(페이지 파일·캐시·스왑 등)을 함께 분석해 노이즈를 줄입니다. 특히 K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안을 설계할 때는 이런 접근이 중요합니다.
  • 자동 복구·런북: 각 경보에 연동된 런북을 준비합니다(예: cordon→drain→노드 교체·스케일업, kubelet 재시작, 시스템 캐시 정리). 반복되는 절차는 Operator·플레이북·Kubernetes Jobs 등으로 자동화하고, 성공·실패 로그를 남겨 후속 조치로 연결합니다. 체크리스트 예: 1) 영향 범위 확인 2) 자동화 실행·모니터링 3) 복구 후 정상성 검증.
  • 정책 검증(CI): 리소스 요청·한계, PDB, QoS 클래스, Admission Webhook 규칙을 CI 파이프라인에서 정적·동적 검사로 검증합니다. 퍼포먼스 테스트와 소규모 카오스 테스트로 메모리 압박 상황에서 정책이 의도대로 작동하는지 확인하세요.
  • 포스트모템·SLA 연계: 사고 후에는 RCA와 영향을 정량화된 지표(요인, 재발률, MTTR)를 기록해 SLO/SLA 영향도를 평가하고 개선 항목을 우선순위화합니다. 런북·자동화·CI 규칙을 변경할 때는 반드시 재검증해 회귀를 방지합니다.

경험에서 배운 점

운영 중인 Kubernetes 클러스터에서 메모리 압박으로 OOMKill이 급증할 때, 대개는 리소스 요청·제한 미설정, 노드 레벨 예약(system/kubelet reserved) 미구성, 그리고 모니터링·알림의 부재가 결합된 경우였습니다. 흔히 보는 실수로는 '컨테이너에 limit을 설정하지 않으면 노드 전체가 위험해진다'는 기본 인식의 부족, 팀별 과도한 배포 허용, 그리고 kubelet의 eviction 설정을 기본값으로 방치하는 것이 있습니다. 문제 발생 시에는 신속한 노드 격리와 드레인이 중요합니다. 동시에 요청/제한·예약·우선순위·쿼터·모니터링 같은 구조적 예방을 병행해야 재발을 막을 수 있습니다. 이 내용은 K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안의 핵심을 담고 있습니다.

실무 체크리스트(우선순위 따라 적용):
- 모든 네임스페이스에서 리소스 요청(requests)과 제한(limits)을 강제하세요. LimitRange와 Admission 컨트롤러로 적용하고, 팀별 ResourceQuota로 과다 배포를 차단합니다.
- kubelet 설정에서 systemReserved와 kubeReserved로 노드 시스템용 메모리를 확보하고, evictionHard/evictionSoft의 메모리 임계값을 적절히 조정합니다.
- 중요 서비스에는 PriorityClass(예: critical, important)를 지정해 불필요한 파드가 먼저 종료되도록 하고, QoS 설계에서는 GUARANTEED를 우선 고려하세요.
- 노드 모니터링은 사용 가능한 메모리, 페이지 캐시, swap 사용량 등을 포함해야 하며, 파드 종료 사유(OOMKilled)에 대한 알림을 반드시 설정합니다.
- 운영 중 이상이 감지되면 해당 노드를 cordon으로 차단한 뒤 drain으로 파드를 옮겨 영향 범위를 축소합니다. 필요 시 인스턴스 타입 업그레이드나 노드 추가로 사이징을 조정하세요.
- 리소스 관리 정책은 LimitRange/ResourceQuota와 네임스페이스별 책임자 지정으로 운영하고, CI/CD 파이프라인에서 리소스 검증을 자동화해 휴먼 에러를 줄입니다.
- 조사 시에는 kubelet 로그와 dmesg(OOM killer 관련 로그), kube-apiserver의 이벤트(파드 종료 사유), 그리고 노드·파드 메트릭을 신속히 수집해 근본 원인을 분석하세요.
- 사례: 개발 네임스페이스에서 메모리 요청을 제한하지 않아 OOMKill이 급증한 적이 있습니다. LimitRange와 ResourceQuota를 도입하고 우선순위를 조정하자 서비스가 안정되었습니다.

AI 생성 이미지: K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안
AI 생성 이미지: K8s 노드 메모리 압박으로 OOMKill 폭증 대응 방안

댓글

이 블로그의 인기 게시물

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%);"> 레이어 팝업 내용 <...