배포했는데 Pod가 Running도 Error도 아닌 Pending에서 몇 분째 움직이지 않는 상황, 쿠버네티스를 운영하다 보면 반드시 만나게 됩니다. Pending은 오류처럼 보이지 않아서 더 헷갈립니다. 컨테이너 로그도 없고, 재시작 카운트도 0이고, 그냥 “대기 중”이기 때문입니다.
결론부터 말하면 Pending은 스케줄러가 이 Pod를 올릴 노드를 아직 찾지 못했다는 뜻이고, 원인은 kubectl describe pod의 FailedScheduling 이벤트 메시지에 그대로 적혀 있습니다. Insufficient cpu/memory는 리소스 부족, untolerated taint는 Taint 문제, didn't match node selector는 라벨 불일치, unbound PersistentVolumeClaims는 스토리지 대기입니다. 이 글에서는 메시지별 원인과 해결 순서를 정리합니다.
Pod가 뜬 뒤 반복 재시작된다면 CrashLoopBackOff 해결 가이드, 이미지 문제로 멈춘다면 ImagePullBackOff 해결 가이드를 보세요. Pending까지 합치면 Pod가 안 뜨는 3대 상태가 모두 정리됩니다.
핵심 요약
- Pending = 스케줄링 전 단계. 노드가 정해지지 않았거나, 정해졌지만 볼륨 등 준비가 안 된 상태입니다.
- 진단 시작은 언제나
kubectl describe pod의 Events입니다. FailedScheduling 메시지에 “왜 안 되는지”가 노드 수 단위로 집계되어 나옵니다. - 가장 흔한 원인은 requests 과다로 인한 Insufficient cpu/memory입니다. limits가 아니라 requests가 스케줄링 기준입니다.
- Taint/Toleration, nodeSelector/Affinity는 “자리는 있는데 조건이 안 맞는” 계열입니다. 노드 라벨과 Taint를 실제로 조회해 대조해야 합니다.
- PVC가
Pending이면 Pod도Pending입니다. StorageClass와WaitForFirstConsumer동작을 함께 확인하세요. ContainerCreating에서 멈추는 것은 스케줄링 이후 단계(볼륨 마운트·CNI)로, 원인 계열이 다릅니다.
1. Pending이 의미하는 것 — 스케줄링 파이프라인
Pod가 Running까지 가는 경로는 대략 다음과 같습니다.
생성 → [Pending] 스케줄러가 노드 선택
→ [Pending] 볼륨 바인딩·노드 배정 완료 대기
→ [ContainerCreating] 이미지 pull, 볼륨 마운트, 네트워크 설정
→ [Running]
즉 Pending은 크게 두 종류입니다. 스케줄 실패(노드를 못 정함 — FailedScheduling 이벤트 발생)와 스케줄은 됐지만 준비 대기(주로 볼륨). Events를 보면 어느 쪽인지 바로 구분됩니다.
2. 첫 번째 명령 — describe로 FailedScheduling 읽기
$ kubectl describe pod api-6f9c77b4d9-tk2plq | tail -n 8
Events:
Type Reason Message
---- ------ -------
Warning FailedScheduling 0/6 nodes are available:
3 Insufficient memory,
2 node(s) had untolerated taint {dedicated: gpu},
1 node(s) didn't match Pod's node affinity/selector.
이 메시지는 “6개 노드 각각이 왜 탈락했는지”의 집계표입니다. 탈락 사유별로 아래 섹션으로 분기하면 됩니다.
| FailedScheduling 메시지 | 원인 계열 | 해당 섹션 |
|---|---|---|
Insufficient cpu / Insufficient memory | 리소스 부족 | 3 |
had untolerated taint | Taint/Toleration | 4 |
didn't match Pod's node affinity/selector | 라벨·어피니티 불일치 | 5 |
unbound immediate PersistentVolumeClaims | PVC 바인딩 실패 | 6 |
node(s) were unschedulable | cordon·드레인된 노드 | 7 |
didn't match pod anti-affinity rules | 안티어피니티 충돌 | 5 |
| 이벤트 없이 Pending 지속 | 스케줄러·쿼터·웹훅 등 | 8 |
3. 원인 1 — Insufficient cpu/memory: 가장 흔한 범인
스케줄러는 노드의 할당 가능량(allocatable)에서 이미 배치된 Pod들의 requests 합을 뺀 여유와 새 Pod의 requests를 비교합니다. 실제 사용률이 낮아도 requests가 크면 자리가 없습니다.
# 노드별 requests 할당 현황
kubectl describe node NODE_NAME | grep -A 8 "Allocated resources"
# 어떤 Pod가 requests를 많이 잡는지
kubectl top pods -A --sort-by=memory # 실사용
kubectl get pods -A -o custom-columns=\
NS:.metadata.namespace,NAME:.metadata.name,\
REQ_CPU:.spec.containers[*].resources.requests.cpu,\
REQ_MEM:.spec.containers[*].resources.requests.memory
해결 순서는 다음과 같습니다.
- requests 현실화: 실사용(
kubectl top) 대비 과도한 requests를 줄입니다. “일단 4Gi”로 잡아둔 값들이 누적된 경우가 대부분입니다. - 큰 Pod 분리: 유난히 큰 requests의 Pod 하나가 조각난 여유 공간에 못 들어가는 경우, 노드풀을 분리하거나 Pod를 쪼갭니다.
- 노드 증설·오토스케일러: Cluster Autoscaler가 있다면 Pending Pod가 트리거가 되는데, 노드 그룹 최대치에 걸려 안 늘어나는 경우를 먼저 확인하세요.
- 우선순위 설계: PriorityClass를 쓰면 중요 워크로드가 낮은 우선순위 Pod를 밀어내고(preemption) 자리를 확보할 수 있습니다. 반대로 내 Pod가 계속 밀려나는 원인이 되기도 합니다.
4. 원인 2 — untolerated taint: 노드가 거부하는 경우
Taint는 노드가 “조건에 맞는 Pod만 받겠다”고 선언하는 장치입니다. GPU 노드, 스팟 노드, 시스템 전용 노드에 흔히 걸려 있습니다.
# 노드의 Taint 확인
kubectl get nodes -o custom-columns=\
NAME:.metadata.name,TAINTS:.spec.taints[*].key
# Pod에 Toleration 추가
spec:
tolerations:
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
- 클러스터의 모든 노드가 전용 Taint로 나뉘어 있는데 새 워크로드에 Toleration을 안 넣는 실수가 흔합니다.
- 반대로 Toleration을 너무 넓게(모든 Taint 허용) 주면 시스템 노드에 애플리케이션이 올라가는 사고가 납니다. 필요한 키만 정확히 허용하세요.
node.kubernetes.io/not-ready같은 자동 Taint가 보이면 노드 자체의 상태 문제입니다(7번 참고).
5. 원인 3 — nodeSelector·Affinity 불일치
“이런 노드에만 올려라”는 조건이 실제 노드 라벨과 안 맞는 경우입니다.
# Pod가 요구하는 조건
kubectl get pod POD -o jsonpath='{.spec.nodeSelector}'
# 그 라벨을 가진 노드가 실제로 있는지
kubectl get nodes -l disktype=ssd
- 라벨 오타(
disktypevsdiskType), 노드풀 교체 후 라벨 누락이 단골 원인입니다. requiredDuringScheduling...어피니티는 조건을 못 맞추면 영원히 Pending입니다. 선호 조건이면preferred...로 완화할 수 있는지 검토하세요.- Pod Anti-Affinity도 자주 놓칩니다. “같은 앱을 노드당 1개만” 규칙이 있는데 노드가 replica 수보다 적으면 남는 replica는 계속 Pending입니다.
topologySpreadConstraints의whenUnsatisfiable: DoNotSchedule도 같은 효과를 냅니다.
6. 원인 4 — PVC 대기: 스토리지가 발목을 잡는 경우
Pod가 참조하는 PVC가 바인딩되지 않으면 Pod는 뜰 수 없습니다.
kubectl get pvc # STATUS가 Pending인지 확인
kubectl describe pvc DATA-PVC # 실패 사유 확인
- StorageClass 부재·오타: 지정한 StorageClass가 클러스터에 없으면 PVC가 영원히 Pending입니다.
kubectl get storageclass로 확인하세요. - WaitForFirstConsumer 오해: 이 모드의 StorageClass는 Pod가 스케줄될 때까지 PVC가 Pending인 것이 정상입니다. PVC Pending만 보고 스토리지 문제로 단정하지 마세요. 이때는 Pod 쪽 FailedScheduling 사유가 진짜 원인입니다.
- 가용영역(AZ) 불일치: 볼륨이 A존에 있는데 스케줄 가능한 노드가 B존에만 있으면
volume node affinity conflict가 발생합니다. 노드풀과 볼륨의 존 배치를 맞춰야 합니다. - 용량·쿼터 초과: 클라우드 디스크 쿼터 소진, 프로비저너 오류는 PVC describe 이벤트에 나타납니다.
7. 원인 5 — unschedulable: 노드가 막혀 있는 경우
kubectl get nodes
# STATUS에 SchedulingDisabled / NotReady가 보이는지
SchedulingDisabled는 누군가kubectl cordon했거나 업그레이드 드레인 중이라는 뜻입니다. 작업이 끝났다면kubectl uncordon NODE로 풉니다.NotReady노드는 kubelet·네트워크·디스크 문제입니다.kubectl describe node의 Conditions(MemoryPressure, DiskPressure, Ready)를 확인하세요.- 클러스터 업그레이드 자동화가 실패해 절반이 cordon 상태로 남아 있는 경우도 종종 있습니다.
8. 이벤트가 없는 Pending — 드문 경우들
- ResourceQuota 초과: 네임스페이스 쿼터를 넘으면 보통 Pod 생성 자체가 거부되지만, Deployment의 ReplicaSet 이벤트(
kubectl describe rs)에 실패 사유가 숨어 있는 경우가 있습니다. - 스케줄러 문제: 커스텀
schedulerName을 지정했는데 해당 스케줄러가 없으면 어떤 이벤트도 없이 Pending입니다. - Admission Webhook 지연: 웹훅 서비스 장애로 생성 파이프라인이 막히는 경우 API 서버 로그·웹훅 설정을 확인합니다.
- 대규모 클러스터의 일시 지연: 수백 Pod 동시 배포 직후의 짧은 Pending은 정상 동작일 수 있습니다. “몇 분 이상 지속”될 때만 위 진단을 시작하세요.
9. ContainerCreating과 구분하기
스케줄은 됐는데 ContainerCreating에서 오래 멈춘다면 원인 계열이 다릅니다.
| 상태 | 단계 | 주요 원인 |
|---|---|---|
| Pending | 노드 미배정 | 리소스·Taint·라벨·PVC 바인딩 |
| ContainerCreating | 노드 배정 후 준비 | 볼륨 마운트 실패, Secret/ConfigMap 없음, CNI 오류 |
| ImagePullBackOff | 이미지 준비 | 별도 가이드 참고 |
ContainerCreating 장기화의 단골은 MountVolume.SetUp failed(볼륨·Secret 마운트 실패)와 CNI 플러그인 문제(failed to set up pod network)입니다. 이 역시 describe Events에 원문이 남습니다.
10. 흔한 실수
실수 1. limits만 보고 requests를 안 본다
스케줄링 기준은 requests입니다. limits를 아무리 줄여도 requests가 크면 Pending은 그대로입니다.
실수 2. Pod를 지웠다 다시 만들며 기다린다
조건이 그대로면 결과도 그대로입니다. FailedScheduling 메시지의 탈락 사유를 먼저 해소하세요.
실수 3. 클러스터 전체 여유만 보고 판단한다
클러스터 합계로는 여유가 있어도 단일 노드에 Pod 하나가 통째로 들어갈 자리가 없으면 Pending입니다. 리소스는 노드 단위로 봐야 합니다.
실수 4. WaitForFirstConsumer의 PVC Pending을 장애로 오인한다
이 모드에서는 Pod가 먼저, PVC가 나중입니다. Pod의 스케줄 실패 사유를 고치면 PVC는 따라서 바인딩됩니다.
실전 체크리스트
kubectl describe pod에서 FailedScheduling 메시지의 탈락 사유별 노드 수를 확인했다.- Pod의 requests와 노드별 Allocated resources를 대조했다.
- 노드 Taint와 Pod Toleration을 대조했다.
- nodeSelector·Affinity 라벨을 가진 노드가 실제 존재하는지 확인했다.
- PVC 상태와 StorageClass(볼륨 바인딩 모드 포함)를 확인했다.
- cordon·NotReady 노드가 없는지
kubectl get nodes로 확인했다. - 해결 후 같은 원인이 재발하지 않도록 requests 기준·라벨 규칙을 문서화했다.
마치며
Pending은 장애라기보다 스케줄러가 남긴 판정문입니다. FailedScheduling 메시지는 노드 하나하나가 왜 탈락했는지를 이미 말해주고 있으므로, 메시지를 읽고 리소스·Taint·라벨·스토리지 중 어느 계열인지 분류하는 것이 해결의 전부라고 해도 과언이 아닙니다.
이 글로 CrashLoopBackOff(런타임), ImagePullBackOff(이미지), Pending(스케줄링)까지 Pod가 안 뜨는 3대 상태의 진단 경로가 완성됐습니다. 세 글의 첫 명령이 모두 kubectl describe pod라는 점만 기억해도 현장에서 헤매는 시간이 크게 줄어들 것입니다.
FAQ
Q1. Pending Pod는 얼마나 기다려야 하나요?
스케줄러는 주기적으로 재시도하므로 원인이 해소되면(노드 증설, 자원 반납 등) 자동으로 배치됩니다. 반대로 조건 불일치형 원인은 시간이 해결해주지 않습니다. 몇 분 이상 지속되면 바로 describe를 확인하세요.
Q2. 0/6 nodes are available인데 사유 합계가 6개보다 많아 보입니다.
한 노드가 여러 사유로 탈락하면 사유별 집계에 중복 산입될 수 있습니다. 숫자 합계보다 “어떤 사유가 존재하는가”를 기준으로 분기하는 것이 실용적입니다.
Q3. Cluster Autoscaler가 있는데 노드가 안 늘어납니다.
노드 그룹 최대 크기 도달, 새 노드로도 만족 불가한 조건(Taint·라벨·존), 클라우드 쿼터 초과가 3대 원인입니다. 오토스케일러 로그와 이벤트를 확인하세요.
Q4. 특정 Deployment의 replica 일부만 Pending입니다.
Anti-Affinity나 topologySpreadConstraints로 “노드/존당 1개” 제약이 있는데 배치 가능한 노드·존 수가 replica 수보다 적은 전형적 패턴입니다. 제약을 완화하거나 노드를 늘려야 합니다.
참고 공식 문서
- Kubernetes — Scheduling and Eviction
- Kubernetes — Taints and Tolerations
- Kubernetes — Storage Classes
함께 읽으면 좋은 글
'트러블슈팅 & 장애 대응' 카테고리의 다른 글
| Kubernetes ImagePullBackOff 해결 가이드 — 이미지·인증·네트워크 원인별 점검 (0) | 2026.08.09 |
|---|---|
| Kubernetes CrashLoopBackOff 해결 가이드 — 로그·이벤트·Probe·OOM 점검 (0) | 2026.07.26 |
| Kafka Consumer Lag 원인과 해결 방법: 운영 장애 기준으로 정리 (0) | 2026.07.15 |