Kubernetes Pod Pending 해결법: FailedScheduling 원인별 실전 점검 가이드

Kubernetes를 운영하다 보면 Deployment를 배포했는데 Pod가 Pending 상태에서 움직이지 않는 경우가 있습니다. 재시작부터 해보거나 무작정 노드를 증설하기 전에, 스케줄러가 남긴 이벤트를 읽으면 대부분의 원인을 빠르게 찾을 수 있습니다.

이 글에서는 실무에서 자주 만나는 FailedScheduling 메시지를 기준으로 CPU·메모리 부족, taint, nodeSelector, PVC, Pod 수 제한 문제를 순서대로 점검하는 방법을 정리합니다.

1. Pending은 장애 원인이 아니라 현재 상태다

Pending은 Pod 객체가 생성됐지만 아직 실행할 노드가 결정되지 않았거나, 컨테이너 실행에 필요한 준비가 끝나지 않았다는 뜻입니다. 따라서 kubectl get pods 결과만 보고는 원인을 알 수 없습니다.

kubectl get pods -A --field-selector=status.phase=Pending

문제가 발생한 Pod를 찾았다면 가장 먼저 상세 정보와 이벤트를 확인합니다.

kubectl describe pod <pod-name> -n <namespace>
kubectl events -n <namespace> --for pod/<pod-name>

describe 출력의 맨 아래 Events 영역에 있는 Reason과 Message가 핵심입니다. 여러 메시지가 반복된다면 가장 최근의 Warning / FailedScheduling부터 읽습니다.

2. 가장 흔한 원인: CPU 또는 메모리 부족

다음과 같은 메시지가 보인다면 Pod가 요청한 리소스를 수용할 노드가 없다는 뜻입니다.

0/3 nodes are available: 3 Insufficient cpu.
0/3 nodes are available: 2 Insufficient memory.

Kubernetes 스케줄러는 현재 사용률이 아니라 Pod에 설정된 resources.requests의 합계를 기준으로 배치합니다. 모니터링 화면에서 CPU가 한가해 보여도, 이미 예약된 request가 많으면 새 Pod는 배치되지 않습니다.

kubectl top nodes
kubectl describe nodes
kubectl get pod <pod-name> -n <namespace> -o yaml

점검 포인트

  • requests 값이 실제 필요량보다 과도하게 설정됐는지 확인
  • 한 노드의 allocatable보다 큰 CPU·메모리를 단일 Pod가 요청하는지 확인
  • 사용하지 않는 워크로드가 리소스를 예약하고 있는지 확인
  • 클러스터 오토스케일러가 있다면 증설을 막는 제한 또는 오류가 있는지 확인

해결 방법은 requests를 무조건 낮추는 것이 아닙니다. 실제 사용량과 피크를 확인해 적절히 조정하고, 용량 자체가 부족하다면 노드 증설 또는 불필요한 워크로드 정리가 필요합니다.

3. Taint와 Toleration 불일치

노드에 NoSchedule taint가 있지만 Pod에 대응하는 toleration이 없으면 스케줄러는 해당 노드를 후보에서 제외합니다.

0/3 nodes are available: 3 node(s) had untolerated taint.

현재 노드의 taint를 확인합니다.

kubectl get nodes -o custom-columns=NAME:.metadata.name,TAINTS:.spec.taints
kubectl describe node <node-name> | grep -A 3 Taints

특정 워크로드가 해당 노드에서 실행되어야 한다면 Pod spec에 정확히 일치하는 toleration을 추가합니다.

tolerations:
- key: "workload"
  operator: "Equal"
  value: "batch"
  effect: "NoSchedule"

다만 control-plane이나 장애 상태의 노드에 설정된 taint를 원인 확인 없이 제거하는 것은 피해야 합니다. memory-pressure, disk-pressure, not-ready 같은 taint는 노드 상태 이상을 알려주는 신호일 수 있습니다.

4. nodeSelector와 Affinity 조건이 너무 엄격한 경우

아래 메시지는 Pod가 요구하는 라벨을 가진 노드가 없거나 affinity 조건을 만족할 수 없다는 의미입니다.

node(s) didn't match Pod's node affinity/selector

노드 라벨과 Pod의 스케줄링 조건을 비교합니다.

kubectl get nodes --show-labels
kubectl get pod <pod-name> -n <namespace>   -o jsonpath='{.spec.nodeSelector}'
kubectl get pod <pod-name> -n <namespace> -o yaml

오타, 변경된 노드풀 라벨, 존재하지 않는 zone 지정이 흔한 원인입니다. requiredDuringSchedulingIgnoredDuringExecution은 필수 조건이므로 하나라도 맞지 않으면 배치되지 않습니다. 반드시 필요한 조건이 아니라면 선호 조건인 preferredDuringSchedulingIgnoredDuringExecution으로 완화할 수 있습니다.

5. PVC가 Pending이거나 볼륨의 zone이 맞지 않는 경우

Pod가 사용하는 PersistentVolumeClaim이 바인딩되지 않으면 Pod도 함께 Pending에 머물 수 있습니다.

kubectl get pvc -n <namespace>
kubectl describe pvc <pvc-name> -n <namespace>
kubectl get storageclass

확인할 항목은 다음과 같습니다.

  • StorageClass 이름이 실제로 존재하는가
  • 기본 StorageClass가 지정돼 있는가
  • 동적 프로비저너 또는 CSI controller가 정상인가
  • 요청한 용량과 access mode를 지원하는가
  • PV의 nodeAffinity 또는 zone과 Pod가 배치될 노드가 일치하는가

volumeBindingMode: WaitForFirstConsumer인 StorageClass는 Pod의 스케줄링 조건을 고려해 볼륨을 생성하므로, PVC만 단독으로 보면 Pending이 정상일 수 있습니다. 이때는 Pod와 PVC 양쪽 이벤트를 함께 확인해야 합니다.

6. 노드당 최대 Pod 수에 도달한 경우

Too many pods

CPU와 메모리가 남아 있어도 kubelet 또는 네트워크 설정의 노드당 최대 Pod 수에 도달하면 새 Pod를 배치할 수 없습니다.

kubectl get pods -A -o wide --field-selector spec.nodeName=<node-name>
kubectl describe node <node-name>

Capacity / Allocatable의 pods 값과 현재 실행 중인 Pod 수를 비교합니다. DaemonSet과 시스템 Pod도 개수에 포함됩니다. 불필요한 Pod를 정리하거나 노드풀의 최대 Pod 설정을 검토해야 합니다.

7. Scheduling Gate와 노드 cordon 확인

Pod에 spec.schedulingGates가 있으면 조건이 제거될 때까지 스케줄링 대상이 되지 않습니다.

kubectl get pod <pod-name> -n <namespace>   -o jsonpath='{.spec.schedulingGates}'

또한 노드가 SchedulingDisabled 상태인지 확인합니다.

kubectl get nodes

유지보수가 끝난 노드라면 다음 명령으로 다시 스케줄링을 허용할 수 있습니다.

kubectl uncordon <node-name>

실전 점검 순서 요약

  1. kubectl get pods -A --field-selector=status.phase=Pending로 대상 확인
  2. kubectl describe pod의 Events에서 FailedScheduling 메시지 확인
  3. CPU·메모리 requests와 노드 Allocatable 비교
  4. taint/toleration 및 nodeSelector/affinity 비교
  5. PVC, StorageClass, CSI 상태 확인
  6. 노드별 Pod 수, cordon, schedulingGates 확인

Pending 문제는 추측보다 이벤트 메시지를 정확히 읽는 것이 가장 빠른 해결책입니다. 특히 실제 사용률과 requests를 혼동하지 않고, Pod와 노드뿐 아니라 PVC 이벤트까지 함께 보면 원인 파악 시간이 크게 줄어듭니다.

참고 자료

댓글

이 블로그의 인기 게시물

10.15 부동산 대책, 오피스텔도 LTV 40%인가요? 혼선 정리

애플 비전 프로 새 밴드 착용감 어떨까? Dual Knit Band 착용 경험 리뷰