노드 압력 축출

노드 압력 축출 (Node-pressure Eviction)

노드 압력 축출은 kubelet이 노드의 리소스를 회수하기 위해 Pod를 선제적으로 종료하는 과정이에요.

kubelet은 클러스터 노드의 메모리, 디스크 공간, 파일시스템 inode 같은 리소스를 모니터링해요. 하나 이상의 리소스가 특정 소비 수준에 도달하면 kubelet이 노드의 하나 이상의 Pod를 선제적으로 실패시켜 리소스를 회수하고 자원 고갈(starvation)을 방지해요.

노드 압력 축출 중 kubelet은 선택된 Pod의 phaseFailed로 설정하고 Pod를 종료해요.

노드 압력 축출은 API 기반 축출과 달라요. kubelet은 구성된 PodDisruptionBudget이나 Pod의 terminationGracePeriodSeconds를 존중하지 않아요. soft 축출 임계값을 쓰면 eviction-max-pod-grace-period를 존중하고, hard 축출 임계값을 쓰면 0s grace period(즉시 종료)를 사용해요.

자가 치유 동작

kubelet은 최종 사용자 Pod를 종료하기 전에 노드 수준 리소스 회수를 시도해요. 예를 들어 디스크가 고갈되면 사용하지 않는 컨테이너 이미지를 제거해요. 축출된 Pod가 StatefulSet이나 Deployment 같은 워크로드 관리 객체가 교체하는 관리 대상이라면, 컨트롤 플레인(kube-controller-manager)이 축출된 Pod 대신 새 Pod를 만들게 됩니다.

static pod 자가 치유

리소스 압력이 있는 노드에서 static pod를 실행 중이라면 kubelet이 그 static Pod를 축출할 수 있고, static Pod는 항상 그 노드에서 실행하겠다는 의도이므로 교체를 만들려고 해요.

축출 신호와 임계값

kubelet은 축출 결정에 다음 파라미터를 사용해요.

  • 축출 신호 (Eviction signals)
  • 축출 임계값 (Eviction thresholds)
  • 모니터링 간격 (Monitoring intervals)

축출 신호

축출 신호는 특정 시점의 특정 리소스 현재 상태예요. kubelet은 축출 신호를 축출 임계값(노드에 있어야 하는 최소 리소스 양)과 비교해 축출을 결정해요.

Eviction Signal Description Linux Only
memory.available node.status.capacity[memory] - node.stats.memory.workingSet
nodefs.available node.stats.fs.available
nodefs.inodesFree node.stats.fs.inodesFree
imagefs.available node.stats.runtime.imagefs.available
imagefs.inodesFree node.stats.runtime.imagefs.inodesFree
pid.available node.stats.rlimit.maxpid - node.stats.rlimit.curproc

메모리 신호

Linux 노드에서 memory.available 값은 free -m 같은 도구가 아니라 cgroupfs에서 파생돼요. free -m은 컨테이너 안에서 동작하지 않기 때문이에요. kubelet은 계산에서 inactive_file을 제외해요 (압력 하에서 회수 가능한 메모리라고 가정).

Windows 노드에서는 GetPerformanceInfo() 호출로 노드의 전역 메모리 commit 수준을 질의해 CommitLimit에서 CommitTotal을 뺀 값으로 파생돼요.

파일시스템 신호

kubelet은 세 가지 파일시스템 식별자를 인식해요.

  1. nodefs: 로컬 디스크 볼륨, 메모리 기반이 아닌 emptyDir 볼륨, 로그 저장, ephemeral storage 등을 위한 노드의 주 파일시스템 (/var/lib/kubelet 포함).
  2. imagefs: 컨테이너 런타임이 컨테이너 이미지(읽기 전용 레이어)를 저장하는 선택적 파일시스템.
  3. containerfs: 컨테이너 런타임이 컨테이너 쓰기 레이어를 저장하는 선택적 파일시스템.

세 식별자가 항상 세 개의 다른 마운트 포인트를 뜻하는 건 아니에요. 흔한 배치에서 두 개 또는 세 개가 같은 기본 파일시스템을 가리킬 수 있어요.

축출 임계값

축출 임계값 형식은 [eviction-signal][operator][quantity]예요. operator는 < 같은 비교 연산자, quantity는 1Gi 같은 임계값 양이에요. 리터럴 값이나 백분율(%)을 쓸 수 있어요.

예를 들어 노드에 총 10GiB 메모리가 있고 가용 메모리가 1GiB 아래로 떨어지면 축출하고 싶다면, memory.available<10% 또는 memory.available<1Gi로 정의할 수 있어요 (둘 다는 사용 불가).

Soft 축출 임계값

soft 임계값은 관리자가 지정한 grace period와 함께 사용돼요. kubelet은 grace period가 초과될 때까지 Pod를 축출하지 않아요.

  • eviction-soft: memory.available<1.5Gi 같은 축출 임계값 집합
  • eviction-soft-grace-period: soft 임계값이 얼마나 유지돼야 축출을 트리거하는지 정의 (예: memory.available=1m30s)
  • eviction-max-pod-grace-period: soft 임계값 충족 시 Pod 종료에 사용할 최대 허용 grace period(초)

Hard 축출 임계값

hard 임계값에는 grace period가 없어요. 충족되면 kubelet이 고갈된 리소스를 회수하기 위해 정상 종료 없이 즉시 Pod를 종료해요.

--eviction-hard--system-reserved 플래그를 함께 쓸 수 있어요. 예를 들어 노드가 10GiB 메모리이고 시스템 데몬용 10%를 예약하고 95% 사용률에서 축출하려면:

--eviction-hard=memory.available<500Mi
--system-reserved=memory=1.5Gi

이 구성에서 --system-reserved는 총 메모리의 10% + 축출 임계값 양인 1.5GiB를 시스템용으로 예약해요.

DaemonSet과 노드 압력 축출

Pod 우선순위는 축출 결정의 주요 요인이에요. DaemonSet에 속한 Pod를 kubelet이 축출하지 않길 원하면 그 Pod에 적절한 priorityClassName을 지정해 우선순위를 충분히 높게 해야 해요.

알려진 문제

  • kubelet이 메모리 압력을 즉시 관찰하지 못할 수 있어요: kubelet이 주기적으로 cAdvisor를 폴링하므로, 그 창에 메모리 사용이 급증하면 MemoryPressure를 빠르게 관찰하지 못하고 OOM 킬러가 개입할 수 있어요. --kernel-memcg-notification 플래그로 memcg 알림 API를 활성화할 수 있어요.
  • active_file 메모리는 가용 메모리로 간주되지 않아요: Linux에서 커널은 active LRU 목록의 file-backed 메모리를 active_file로 추적하고, kubelet은 이를 회수 불가능으로 취급해요. 블록 기반 로컬 스토리지를 집중적으로 쓰는 워크로드에서 문제가 될 수 있어요.

더 알아보기 (Learn more)