The PersistentVolumeClaim is stuck in a Pending state because the Kubernetes control plane cannot find a PersistentVolume that matches its requirements.
Common Causes and Fixes
-
No Matching PersistentVolumes Exist:
- Diagnosis:
kubectl get pv - Problem: You have
PersistentVolumeClaimsrequesting specificstorageClassName,accessModes, orcapacity, but noPersistentVolumesare available that satisfy these criteria. - Fix:
- Dynamic Provisioning: If you intend to use dynamic provisioning, ensure your
StorageClassis correctly configured and available. Check its status withkubectl get sc. If it’s missing or misconfigured, create/update it. For example, to create a StorageClass for AWS EBS:
Then, ensure yourapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: gp2-dynamic provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain volumeBindingMode: ImmediatePersistentVolumeClaimreferences thisStorageClass:
This works because theapiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc spec: storageClassName: gp2-dynamic # Must match the StorageClass name accessModes: - ReadWriteOnce resources: requests: storage: 10Giprovisionerfield tells Kubernetes which external storage system (like AWS EBS, GCE PD, Ceph) to contact to create a new volume on demand when aPersistentVolumeClaimrequests it and no suitable staticPersistentVolumeis found. - Static Provisioning: If you are using static provisioning, you need to manually create
PersistentVolumesthat match thePersistentVolumeClaim’sstorageClassName,accessModes, andcapacity. For example, to create aPersistentVolumefor NFS:
And ensure yourapiVersion: v1 kind: PersistentVolume metadata: name: my-static-pv spec: capacity: storage: 50Gi volumeMode: Filesystem accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Recycle storageClassName: nfs-storage mountPath: "/mnt/nfs/data" # This is specific to the PV definition, not typically used by K8s itself for mounting nfs: server: 192.168.1.100 path: "/exports/data"PersistentVolumeClaimmatches:
This works because theapiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-nfs-pvc spec: accessModes: - ReadWriteMany storageClassName: nfs-storage # Must match the PV's storageClassName resources: requests: storage: 50GistorageClassNameacts as a label that Kubernetes uses to bind aPersistentVolumeClaimto a suitablePersistentVolume. When they match, the claim can be satisfied.
- Dynamic Provisioning: If you intend to use dynamic provisioning, ensure your
- Diagnosis:
-
Incorrect
storageClassNamein PVC:- Diagnosis:
kubectl get pvc <pvc-name> -o yamlandkubectl get sc - Problem: The
storageClassNamespecified in yourPersistentVolumeClaimdoes not exist in your cluster or has a typo. - Fix: Correct the
storageClassNamein yourPersistentVolumeClaimYAML to match an existingStorageClass. If you want to use the default provisioner, you can omit thestorageClassNamefield entirely if a defaultStorageClassis set in your cluster. To set a defaultStorageClass:
This works becauseapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: default-storage annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: kubernetes.io/no-provisioner # Or your actual provisionerstorageClassNameis the primary mechanism for selecting a volume provisioner or a pre-provisionedPersistentVolume. If it doesn’t resolve, the claim cannot be bound.
- Diagnosis:
-
Volume Binding Mode (Delayed Binding):
- Diagnosis:
kubectl get pvc <pvc-name> -o yamland check thevolumeBindingModein the associatedStorageClass(kubectl get sc <storage-class-name> -o yaml). - Problem: If
volumeBindingModeis set toWaitForFirstConsumeron theStorageClass, thePersistentVolumewill not be provisioned or bound until a Pod that uses thePersistentVolumeClaimis scheduled. If no Pod is scheduled, or if the Pod cannot be scheduled for other reasons, the PVC will remainPending. - Fix:
- If you intend to use
WaitForFirstConsumer, ensure that the Pod using the PVC can be scheduled. Check Pod scheduling issues withkubectl describe pod <pod-name>. - Alternatively, change
volumeBindingModetoImmediatein yourStorageClassdefinition.
This works becauseapiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: my-storage-class provisioner: kubernetes.io/aws-ebs volumeBindingMode: Immediate # Change this from WaitForFirstConsumerImmediatebinding ensures that aPersistentVolumeis provisioned and bound as soon as thePersistentVolumeClaimis created, regardless of whether a Pod is ready to consume it. This allows the PVC to be satisfied sooner.
- If you intend to use
- Diagnosis:
-
Insufficient Available
PersistentVolumes(Static Provisioning):- Diagnosis:
kubectl get pvandkubectl get pvc <pvc-name> -o yaml - Problem: You are using static
PersistentVolumes, but all availablePersistentVolumesare already bound to otherPersistentVolumeClaimsor are not available due toPersistentVolumeReclaimPolicy(e.g.,Retainand the PV is not explicitly released). - Fix:
- Create more
PersistentVolumesthat match the requirements of yourPersistentVolumeClaims. - If a
PersistentVolumeis in aReleasedstate and itspersistentVolumeReclaimPolicyisRetain, you may need to manually delete thePersistentVolumeobject from Kubernetes and ensure the underlying storage is cleaned up, then re-create thePersistentVolumeobject if you want to reuse it. Be extremely cautious with this. - If a
PersistentVolumeis in aFailedstate, investigate the underlying storage provisioner logs.
This works because Kubernetes relies on the# Example of manually releasing and cleaning up a PV (USE WITH EXTREME CAUTION) # 1. Ensure the pod using the PVC is deleted. # 2. If the PV's reclaim policy is Retain, you might need to manually delete the underlying storage. # 3. Delete the PV object: kubectl delete pv <pv-name> # 4. Re-create the PV object if you intend to reuse it and have cleaned up the storage.statusfield of thePersistentVolumeobject to determine its availability. If all suitable PVs are in aBoundstate or unavailable for other reasons, no match can be found.
- Create more
- Diagnosis:
-
Incorrect
accessModes:- Diagnosis:
kubectl get pvc <pvc-name> -o yamlandkubectl get pv -o yaml - Problem: The
accessModesrequested by thePersistentVolumeClaim(e.g.,ReadWriteOnce,ReadOnlyMany,ReadWriteMany) are not supported by any availablePersistentVolumesthat otherwise match. For example, requestingReadWriteManywhen all available PVs only supportReadWriteOnce. - Fix: Adjust the
accessModesin yourPersistentVolumeClaimto match those offered by an availablePersistentVolume, or create/configure aPersistentVolumethat supports the desiredaccessModes.
This works because# PVC requesting ReadWriteOnce apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc-rwo spec: accessModes: - ReadWriteOnce # This mode is widely supported resources: requests: storage: 10Gi # PV supporting ReadWriteOnce apiVersion: v1 kind: PersistentVolume metadata: name: my-pv-rwo spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce hostPath: # Example for local storage path: "/mnt/data/rwo"accessModesdefine how a volume can be mounted by nodes. APersistentVolumeClaimcan only be bound to aPersistentVolumethat offers at least one compatibleaccessMode.
- Diagnosis:
-
Storage Provisioner Issues:
- Diagnosis:
kubectl get pods -n kube-system(look for CSI driver pods or provisioner pods),kubectl logs <provisioner-pod-name> -n <namespace> - Problem: If you are using dynamic provisioning, the storage provisioner (e.g., a CSI driver or an in-tree provisioner) might be failing. This could be due to network issues, authentication problems with the cloud provider, misconfiguration of the provisioner, or underlying storage system errors.
- Fix: Examine the logs of your storage provisioner pods for errors. Troubleshoot connectivity, credentials, and configuration as indicated by the logs. For example, if using AWS EBS CSI driver, check the
aws-ebs-csi-driverpods.
This works because the provisioner is the component responsible for actually creating the storage volume in your cloud provider or storage system when requested by Kubernetes. If it fails, no# Example: Check logs for AWS EBS CSI driver controller pod kubectl logs <aws-ebs-csi-driver-controller-pod-name> -n kube-systemPersistentVolumeis created, and thePersistentVolumeClaimremainsPending.
- Diagnosis:
Once all these issues are resolved, your PersistentVolumeClaim should transition to a Bound state. The next common problem you might encounter is Pods failing to start due to issues with the underlying storage becoming available or mountable by the node.