- Published on
K8s Pod Pending? PVC 바인딩 실패 7가지
- Authors
- Name
- 스타차일드
- https://x.com/ETFBITX
Pod가 Pending 상태로 오래 멈춰 있으면 대부분 스케줄링(리소스 부족, 노드 셀렉터 불일치 등)이나 스토리지 바인딩(PVC 미바인딩) 문제로 좁혀집니다. 그중에서도 PVC 바인딩 실패는 증상이 단순해 보이지만 원인이 다양하고, 클러스터/스토리지 플러그인/정책이 얽혀 있어 시간을 잡아먹습니다.
이 글은 Pod Pending의 원인이 PVC 바인딩인지 빠르게 확인하고, 실무에서 자주 만나는 PVC 바인딩 실패 7가지 패턴을 이벤트 메시지와 함께 정리합니다. (Pod가 뜬 뒤 CrashLoopBackOff로 넘어가는 케이스는 별도 관점이므로 필요하면 K8s CrashLoopBackOff 원인별 진단·해결 체크리스트도 같이 보시면 흐름이 이어집니다.)
0) 먼저: 진짜 PVC 때문에 Pending인가?
아래 3가지만 보면 대부분 1분 내로 결론이 납니다.
Pod 이벤트 확인
kubectl -n <namespace> describe pod <pod-name>
Events 섹션에서 아래와 비슷한 문구가 보이면 PVC 바인딩/프로비저닝 쪽입니다.
pod has unbound immediate PersistentVolumeClaimswaiting for a volume to be created, either by external provisioner or manually createdfailed to provision volume with StorageClass ...
PVC 상태와 이벤트 확인
kubectl -n <namespace> get pvc
kubectl -n <namespace> describe pvc <pvc-name>
여기서 STATUS가 Pending이면 거의 확정입니다. describe의 Events가 핵심 단서입니다.
StorageClass 확인
kubectl get storageclass
kubectl describe storageclass <sc-name>
provisioner, volumeBindingMode, 파라미터(예: type, encrypted, fsType)를 확인합니다.
1) StorageClass가 없거나 기본 StorageClass가 없다
전형적인 증상
- PVC에
storageClassName을 안 적었는데Pending - 이벤트에
no persistent volumes available for this claim and no storage class is set또는 유사 메시지
원인
클러스터에 기본 StorageClass가 없거나, 기본 지정이 해제되어 PVC가 어떤 프로비저너를 써야 할지 결정하지 못합니다.
해결
- PVC에 명시적으로
storageClassName지정 - 혹은 기본 StorageClass 지정
kubectl patch storageclass <sc-name> -p '{"metadata": {"annotations": {"storageclass.kubernetes.io/is-default-class": "true"}}}'
운영 환경에서는 “기본 SC 하나만 두기”보다, 워크로드별 SC를 명시하는 편이 사고를 줄입니다.
2) StorageClass 프로비저너가 없거나 컨트롤러가 죽어 있음
전형적인 증상
PVC 이벤트에 아래가 자주 뜹니다.
waiting for a volume to be created, either by external provisioner or manually createdno volume plugin matched name ...
원인
CSI 드라이버(예: EBS CSI, Ceph RBD CSI, NFS CSI 등) 컨트롤러가 설치되지 않았거나, 권한/크래시로 동작하지 않습니다.
해결 체크
kubectl -n kube-system get pods | grep -i csi
kubectl -n kube-system logs <csi-controller-pod>
- 컨트롤러/노드 플러그인 모두 떠 있는지
- RBAC 누락으로
Forbidden이 나는지 - 클라우드라면 IRSA/Workload Identity 같은 권한 체인이 맞는지
스토리지 이슈가 네트워크/DNS 문제와 함께 터지는 경우도 많습니다. EKS라면 EKS에서 Pod DNS 실패 - CoreDNS·VPC CNI 점검처럼 기반 레이어도 같이 확인하면 시간을 절약합니다.
3) volumeBindingMode가 WaitForFirstConsumer인데 스케줄링이 막혀 연쇄 Pending
전형적인 증상
- StorageClass에
volumeBindingMode: WaitForFirstConsumer - Pod는
Pending, PVC도Pending - 이벤트에
waiting for first consumer to be created before binding같은 메시지
원인
이 모드는 “Pod가 어느 노드에 스케줄될지 결정된 뒤” 그 노드의 AZ/토폴로지에 맞게 볼륨을 만들도록 설계됐습니다.
그런데 Pod가 애초에 스케줄링이 안 되면(리소스 부족, taint 미허용, 노드 셀렉터 불일치 등) PVC도 계속 Pending으로 남습니다.
해결
kubectl describe pod에서FailedScheduling이유부터 해결- 특히 아래를 자주 놓칩니다.
nodeSelector/nodeAffinity가 존재하지 않는 라벨을 가리킴- 노드에
taint가 있는데toleration없음 - 요청 리소스가 과도함
PVC만 보지 말고 “Pod 스케줄링 원인”을 같이 봐야 하는 대표 케이스입니다.
4) PV가 있어도 PVC와 스펙이 안 맞아 매칭이 실패
동적 프로비저닝이 아니라 정적 PV를 붙이거나, 특정 PV를 의도적으로 재사용할 때 자주 발생합니다.
전형적인 증상
- PV는
Available인데 PVC는Pending - 이벤트에
no persistent volumes available for this claim가 뜸
체크 포인트
PV와 PVC의 아래 조건이 맞아야 바인딩됩니다.
accessModes일치 (예:ReadWriteOnce등)storageClassName일치- 요청 용량
resources.requests.storage가 PV 용량 이하 volumeMode일치 (예:FilesystemvsBlock)selector가 있으면 라벨 매칭
확인 명령
kubectl get pv
kubectl describe pv <pv-name>
kubectl -n <namespace> describe pvc <pvc-name>
실수 예시
PVC는 ReadWriteMany를 요구하는데 PV는 ReadWriteOnce만 제공하는 경우가 흔합니다. 클라우드 블록 스토리지(EBS 등)는 보통 ReadWriteOnce만 지원합니다.
5) 토폴로지(AZ/Zone) 제약으로 볼륨 생성 또는 어태치가 불가능
전형적인 증상
- 멀티 AZ 클러스터에서 특정 노드로는 볼륨 생성/어태치가 안 됨
- 이벤트에
topology또는zone관련 메시지
원인
클라우드 볼륨은 특정 AZ에 종속인 경우가 많습니다. Pod가 다른 AZ 노드에 스케줄되면 볼륨을 붙일 수 없습니다.
해결
WaitForFirstConsumer사용으로 노드 결정 후 해당 AZ에 볼륨 생성- 혹은 노드/파드에 AZ 어피니티를 걸어 의도한 토폴로지로 고정
- 기존 PV 재사용 시 PV의
nodeAffinity(토폴로지 제약)를 확인
kubectl describe pv <pv-name>
Node Affinity 섹션에 특정 zone이 박혀 있으면, 그 zone에서만 사용 가능합니다.
6) 스토리지 쿼터/용량/제한 정책으로 프로비저닝이 거절됨
전형적인 증상
- PVC 이벤트에
exceeded quota,limit,insufficient capacity류 메시지 - 클라우드 API 에러(예: 볼륨 개수 제한, 용량 제한)가 CSI 로그에 남음
원인
- 네임스페이스
ResourceQuota가requests.storage또는 PVC 개수를 제한 - 스토리지 백엔드(클라우드 계정/프로젝트)의 볼륨 개수 제한
- 스토리지 풀 용량 부족(온프레미스 Ceph, vSphere datastore 등)
해결
네임스페이스 쿼터부터 확인합니다.
kubectl -n <namespace> get resourcequota
kubectl -n <namespace> describe resourcequota <rq-name>
스토리지 백엔드 제한은 CSI 컨트롤러 로그에서 API 에러를 확인하는 게 가장 빠릅니다.
kubectl -n kube-system logs <csi-controller-pod>
7) PVC/PV가 삭제 중이거나 Finalizer 때문에 Terminating에 걸림
전형적인 증상
- PVC가
Terminating에서 멈춤 - 같은 이름으로 다시 만들었는데 바인딩이 꼬임
- 이벤트보다 오브젝트 메타데이터에 힌트가 있음
원인
Kubernetes는 리소스 정리를 보장하기 위해 finalizers를 사용합니다. CSI/외부 프로비저너가 백엔드 볼륨 삭제를 완료하지 못하면 PVC/PV가 계속 남아 다음 흐름을 막습니다.
해결
- 우선 왜 삭제가 안 되는지 CSI 로그 확인
- 정말로 “강제 제거”가 필요할 때만 finalizer 제거
kubectl -n <namespace> get pvc <pvc-name> -o json | jq '.metadata.finalizers'
kubectl -n <namespace> patch pvc <pvc-name> -p '{"metadata":{"finalizers":[]}}' --type=merge
주의: finalizer를 제거하면 백엔드 볼륨이 고아 리소스로 남을 수 있습니다. 비용/데이터 보존 정책을 먼저 확인하세요.
문제를 빠르게 좁히는 실전 체크리스트
아래 순서대로 보면 “원인 후보”가 급격히 줄어듭니다.
kubectl -n <namespace> describe pod <pod-name>에서 이벤트가 PVC 관련인지 확인kubectl -n <namespace> describe pvc <pvc-name>이벤트 문구 확보kubectl describe storageclass <sc-name>에서provisioner,volumeBindingMode확인- CSI 컨트롤러 로그에서 실제 실패 원인(API 에러, 권한, 쿼터) 확인
- 정적 PV라면 PV/PVC 스펙 매칭(모드, 용량, SC, 라벨) 검증
- 멀티 AZ라면 토폴로지 제약과 노드 스케줄링을 함께 점검
재현 가능한 예제: 가장 흔한 실패 패턴 2가지
예제 A: 존재하지 않는 StorageClass를 참조
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: not-exist-sc
이 경우 PVC 이벤트에 storageclass.storage.k8s.io "not-exist-sc" not found 류가 남습니다.
예제 B: WaitForFirstConsumer에서 스케줄링이 막혀 연쇄 Pending
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3-wffc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
type: gp3
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: gp3-wffc
---
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
nodeSelector:
nodepool: does-not-exist
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: data
여기서는 PVC만 보면 “기다리는 중”처럼 보이지만, 실제 원인은 nodeSelector로 인해 Pod가 스케줄되지 않는 것입니다.
마무리: 이벤트 문구를 원인으로 바로 매핑하라
PVC 바인딩 실패는 “PVC가 Pending이다”라는 결과는 같아도, 실제 원인은 StorageClass 부재, CSI 장애, 토폴로지, 쿼터, 스펙 미스매치, finalizer 등으로 갈립니다. 가장 빠른 접근은 describe 이벤트 문구를 확보하고, 그 문구가 가리키는 레이어(쿠버네티스 스케줄러, 스토리지 클래스, CSI 컨트롤러, 백엔드 제한)를 즉시 좁히는 것입니다.
운영에서 자주 겪는 패턴은 스토리지 이슈가 다른 장애와 연쇄로 나타나는 점입니다. Pod가 뜬 뒤 반복 재시작까지 이어진다면 Kubernetes CrashLoopBackOff와 OOMKilled(ExitCode 137) 해결도 함께 점검해 두면 장애 대응 시간이 확 줄어듭니다.