/인프라/Kubernetes PVC Stuck in Pending: 6 Causes and a 5-Minute Diagnostic Guide
InfrastructureKubernetesPVC pending

Kubernetes PVC Stuck in Pending: 6 Causes and a 5-Minute Diagnostic Guide

Is kubectl get pvc stuck on Pending and your Pod frozen at ContainerCreating? Pin down which of the six event-specific causes you have—no persistent volumes available, waiting for first consumer, and more—with a decision table and copy-past

Kubernetes PVC Stuck in Pending: 6 Causes and a 5-Minute Diagnostic Guide

When a Kubernetes PVC Won't Leave Pending — 6 Causes, 5-Minute Diagnostic Guide

You rolled out a deployment, but the Pod is stuck forever in ContainerCreating. You run kubectl get pvc and see this:

Bash
$ kubectl get pvc
NAME        STATUS    VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
data-pvc    Pending                                      standard       8m

STATUS=Pending has not cleared for several minutes. A lot of people immediately suspect the scheduler—"are we short on node resources?"—but that's a different problem.

⚠️ The previous post, "Kubernetes Pod Pending," covered cases where the scheduler cannot place a Pod on a node—CPU/memory, taints, insufficient nodes, and so on. This post is a storage-only issue: the PV never binds to the PVC, so the volume never attaches. If the real reason the Pod is Pending is the PVC, staring at the Pod will never give you the answer.

This article is a playbook that maps event text → cause → fix command in three steps, so you can pin down which of the six causes matches the message in front of you within five minutes.

1-Minute First Pass: The Four Commands to Run First

Don't overthink it—run these four as-is right now. 90% of the time the answer is already in the Events section of the first command.

Bash
# ① 가장 중요 — Events 섹션이 원인을 그대로 알려준다
kubectl describe pvc <pvc-name>

# ② 정적 PV가 존재하는지, 어떤 상태인지
kubectl get pv

# ③ StorageClass 목록과 default 여부 확인
kubectl get sc

# ④ 시간순 전체 이벤트(프로비저너 로그 포착)
kubectl get events --sort-by=.metadata.creationTimestamp

Branch on the single line printed under Events at the bottom of describe pvc.

Event textJump to cause
storageclass.storage.k8s.io "xxx" not foundStorageClass name typo
(no events + empty storageClassName)② No default StorageClass
waiting for first consumer to be created before binding③ WaitForFirstConsumer (expected)
no persistent volumes available for this claim④ accessModes/capacity mismatch
failed to provision volume with StorageClass⑤ CSI driver not installed
... could not find ... topology / zone-related⑥ Topology/zone mismatch

Six-Cause Decision Table (the core of this post)

#Event / symptom textCauseCheck commandFix command
storageclass.storage.k8s.io "fast" not foundstorageClassName typo / class does not existkubectl get scFix storageClassName in the PVC manifest to the real name and re-apply
Pending with no events, storageClassName omittedNo default StorageClassConfirm (default) in kubectl get sckubectl patch storageclass <name> -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
waiting for first consumer to be created before bindingWaitForFirstConsumer (expected behavior)kubectl get sc <name> -o yaml | grep volumeBindingModeBinding happens once you actually create the Pod that mounts the PVC
no persistent volumes available for this claimaccessModes/capacity mismatch (static PV)kubectl get pv -o wideFix PVC accessModes, or use RWX-capable storage (NFS/CephFS)
failed to provision volume with StorageClass or infinite PendingCSI driver/provisioner not installedkubectl get csidrivers, kubectl get pods -n kube-system | grep csiInstall the CSI driver (EBS/GCE PD, etc.)
volume node affinity conflict / zone mismatchPV lives in a different AZ from the Podkubectl get pv -o wide, check the node's topology.kubernetes.io/zone labelCreate the PV in the same zone, or use WaitForFirstConsumer for topology-aware provisioning

① StorageClass name typo

This is the most common case and the fastest to fix. Confirm the real name with kubectl get sc and correct the manifest. Managed clusters use different defaults—EKS gp2/gp3, GKE standard-rwo, AKS default—so if you copy-pasted YAML from another cluster, start here.

② No default StorageClass

A PVC that omits storageClassName entirely uses the cluster's default StorageClass. If there is no default at all, it stays Pending forever.

Bash
kubectl get sc
# NAME 옆에 (default)가 없으면 아래로 지정
kubectl patch storageclass standard \
  -p '{"metadata":{"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

③ WaitForFirstConsumer — the most commonly misunderstood case

CODE
Events:
  Normal  WaitForFirstConsumer  ...  waiting for first consumer to be created before binding

This is not a failure; it is expected behavior. A StorageClass with volumeBindingMode: WaitForFirstConsumer deliberately delays binding until a Pod that uses the PVC is actually scheduled. That prevents the PV and Pod from landing in different zones on a multi-AZ cluster. The fix is to create the Pod that mounts the PVC. Leaving a PVC sitting by itself and wondering why it never binds is extremely common.

④ accessModes mismatch (RWO vs RWX)

no persistent volumes available for this claim appears in static provisioning when no PV matches. A common cause is a PVC requesting ReadWriteMany(RWX) while block storage such as EBS or GCE PD does not support RWX. If you truly need RWX, use file storage such as NFS, CephFS, or EFS.

⑤ CSI driver not installed

This has become one of the most frequent causes. After CSI migration of in-tree volume plugins completed, EBS, GCE PD, and similar volumes require a separately installed CSI driver for dynamic provisioning.

Bash
kubectl get csidrivers
kubectl get pods -n kube-system | grep csi
# EKS 예: aws-ebs-csi-driver 애드온 설치 필요

⑥ Capacity and zone topology mismatch

Compare the PV's zone from kubectl get pv -o wide with the node's topology.kubernetes.io/zone label. If the PV is in ap-northeast-2a and the Pod is scheduled to 2c, it will never attach. Topology-aware provisioning (WaitForFirstConsumer) is the right answer.

After each change, watch in real time with:

Bash
kubectl get pvc -w

Static vs. Dynamic Provisioning — the underlying model

  • Static: An admin-created PV binds to a PVC only when capacity/accessModes/storageClassName/selector all match. Any mismatch yields no persistent volumes available.
  • Dynamic: The StorageClass plus a provisioner (CSI) automatically creates a PV that fits the PVC. Without a provisioner, it stays Pending.

Immediate binds as soon as the PVC is created (fine for a single zone). WaitForFirstConsumer delays until the Pod is scheduled (the recommended default for multi-AZ).

Minimal YAML trio for reproduction

YAML
# 1) StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: demo-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
# 2) PVC
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data-pvc
spec:
  accessModes: ["ReadWriteOnce"]
  storageClassName: demo-sc
  resources:
    requests:
      storage: 5Gi
---
# 3) PVC를 마운트하는 Pod (이게 있어야 ③에서 바인딩됨)
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: nginx
    volumeMounts:
    - { name: data, mountPath: /data }
  volumes:
  - name: data
    persistentVolumeClaim:
      claimName: data-pvc

A note from the field

In practice, more than half of PVC Pending cases on multi-AZ EKS/GKE are #③ (expected behavior, but nobody created a Pod) and #⑤ (CSI not installed). When you get a new cluster, make a habit of checking kubectl get sc and kubectl get csidrivers before you even launch a Pod—you'll skip this entire class of wasted hours.

Wrap-up: 5-minute diagnostic checklist

  1. kubectl describe pvc → read the Events line
  2. kubectl get sc → class exists / is default
  3. Check binding mode → if WaitForFirstConsumer, create the Pod first
  4. Confirm accessModes / capacity / zone match
  5. Confirm the driver is installed with kubectl get csidrivers

Prevention tips: Always set a default StorageClass, always specify storageClassName in the manifest, and if you need RWX, pick storage that supports it from the start.

Next post (part 12) preview: When the PVC is Bound but the mount still hangs — fixing Unable to attach or mount volumes / volume node affinity conflict / MountVolume.SetUp failed.

References: official docs

The primary source for the behavior, settings, and errors covered here is the official documentation below. Check it for version-specific options and exact semantics.

FAQ

Q. waiting for first consumer showed up. Is it broken? A. No. That is expected behavior. Binding happens when you actually create and schedule a Pod that mounts the PVC.

Q. Why do I see no persistent volumes available for this claim? A. None of the static PVs match the PVC's accessModes/capacity/storageClassName. It is especially common when you request RWX against block storage.

Q. PVC won't bind on EKS. Is the cluster broken? A. Most of the time the aws-ebs-csi-driver add-on is missing. Check the driver first with kubectl get csidrivers.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.