You created a PersistentVolumeClaim for your application, but it's stuck in Pending state with no bound PersistentVolume. Pods that need the PVC cannot start, and your stateful application is blocked. PVC pending issues are common when setting up storage in Kubernetes and require understanding storage classes, provisioning, and access modes.
Understanding PVC Pending State
A PVC stays pending when Kubernetes cannot find or create a matching PersistentVolume. This happens when no PV matches the PVC's requirements (capacity, access mode, storage class), or dynamic provisioning fails. Understanding the storage subsystem is essential for debugging.
Diagnosis Commands
Check PVC status:
```bash # List PVCs kubectl get pvc -n namespace
# Describe the pending PVC kubectl describe pvc pvc-name -n namespace
# Check events kubectl get events -n namespace --field-selector involvedObject.name=pvc-name ```
Check storage class:
```bash # List storage classes kubectl get storageclass
# Check specific storage class kubectl describe storageclass storage-class-name
# Check default storage class kubectl get storageclass -o jsonpath='{.items[?(@.metadata.annotations.storageclass\.kubernetes\.io/is-default-class=="true")].metadata.name}' ```
Check available PVs:
```bash # List available PVs kubectl get pv
# Check PV capacity and access modes kubectl get pv -o custom-columns='NAME:.metadata.name,CAPACITY:.spec.capacity.storage,ACCESS:.spec.accessModes[0],STATUS:.status.phase,CLASS:.spec.storageClassName'
# Describe specific PV kubectl describe pv pv-name ```
Common Solutions
Solution 1: Fix Missing Storage Class
If PVC references non-existent storage class:
# Check PVC storage class
kubectl get pvc pvc-name -n namespace -o jsonpath='{.spec.storageClassName}'If storage class doesn't exist:
```bash # List available classes kubectl get storageclass
# Create missing storage class kubectl apply -f - <<EOF apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-storage provisioner: kubernetes.io/aws-ebs parameters: type: gp3 reclaimPolicy: Delete allowVolumeExpansion: true EOF ```
Or update PVC to use existing class:
```bash # Delete pending PVC kubectl delete pvc pvc-name -n namespace
# Recreate with correct storage class kubectl apply -f - <<EOF apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-name namespace: namespace spec: storageClassName: existing-class-name accessModes: - ReadWriteOnce resources: requests: storage: 10Gi EOF ```
Solution 2: Fix Provisioner Issues
For dynamic provisioning, check provisioner:
# Check storage class provisioner
kubectl get storageclass storage-class-name -o jsonpath='{.provisioner}'Common provisioner issues:
```bash # AWS EBS provisioner # Check IAM permissions for AWS kubectl describe pods -n kube-system | grep -A 5 ebs
# For CSI drivers, check driver pods kubectl get pods -n kube-system -l app=csi-driver kubectl logs -n kube-system -l app=csi-driver ```
Fix CSI driver issues:
```bash # Check CSI driver status kubectl get csidrivers kubectl describe csidriver driver-name
# Restart CSI controller if needed kubectl rollout restart deployment/csi-controller -n kube-system ```
Solution 3: Fix Capacity Issues
Requested capacity may exceed available storage:
```bash # Check requested capacity kubectl get pvc pvc-name -n namespace -o jsonpath='{.spec.resources.requests.storage}'
# Check available PVs kubectl get pv | grep Available ```
Adjust PVC capacity:
# Reduce request to match available PV
spec:
resources:
requests:
storage: 5Gi # Was 100Gi - too largeOr create larger PV manually:
apiVersion: v1
kind: PersistentVolume
metadata:
name: large-pv
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
storageClassName: standard
hostPath:
path: /mnt/data
type: DirectoryOrCreateSolution 4: Fix Access Mode Mismatch
PVC access mode must match PV:
```bash # Check PVC access mode kubectl get pvc pvc-name -n namespace -o jsonpath='{.spec.accessModes}'
# Check available PVs access modes kubectl get pv -o custom-columns='NAME:.metadata.name,ACCESS:.spec.accessModes' ```
Access mode types: - ReadWriteOnce (RWO) - Single node read/write - ReadOnlyMany (ROX) - Multiple nodes read only - ReadWriteMany (RWX) - Multiple nodes read/write - ReadWriteOncePod (RWOP) - Single pod read/write
Fix access mode:
# Use supported access mode
spec:
accessModes:
- ReadWriteOnce # Most common, most storage supports thisFor ReadWriteMany, use NFS:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage
provisioner: nfs.csi.k8s.io
parameters:
server: nfs-server.example.com
share: /export/dataSolution 5: Fix Volume Binding Mode
WaitForFirstConsumer binding mode delays provisioning:
# Check binding mode
kubectl get storageclass storage-class-name -o jsonpath='{.volumeBindingMode}'If WaitForFirstConsumer, PVC won't bind until pod uses it:
# Immediate binding mode
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-immediate
provisioner: kubernetes.io/aws-ebs
volumeBindingMode: ImmediateFor WaitForFirstConsumer, create pod that uses the PVC:
apiVersion: v1
kind: Pod
metadata:
name: storage-test
spec:
containers:
- name: test
image: busybox
command: ["sleep", "3600"]
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-nameSolution 6: Fix Selector and Label Mismatch
PVC selector must match PV labels:
```bash # Check PVC selector kubectl get pvc pvc-name -n namespace -o jsonpath='{.spec.selector}'
# Check PV labels kubectl get pv --show-labels ```
Fix label matching:
```yaml # PVC with selector spec: selector: matchLabels: environment: production type: fast
# Create PV with matching labels apiVersion: v1 kind: PersistentVolume metadata: name: production-fast-pv labels: environment: production type: fast spec: capacity: storage: 50Gi accessModes: - ReadWriteOnce storageClassName: standard nfs: server: nfs.example.com path: /data/production ```
Solution 7: Fix Cloud Provider Issues
For cloud storage, check provider configuration:
```bash # AWS EBS issues # Check node IAM roles kubectl describe node node-name | grep -A 5 "ProviderID"
# Verify region/zone matching kubectl get pv -o yaml | grep -A 5 zone
# GKE PD issues # Check GCP project and zone kubectl get pv -o yaml | grep -i zone ```
Fix zone/region issues:
# Storage class with allowed topologies
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: regional-storage
provisioner: kubernetes.io/aws-ebs
allowedTopologies:
- matchLabelExpressions:
- key: topology.kubernetes.io/zone
values:
- us-east-1a
- us-east-1bSolution 8: Fix Reclaim Policy Issues
PV reclaim policy affects availability:
# Check PV reclaim policy
kubectl get pv pv-name -o jsonpath='{.spec.persistentVolumeReclaimPolicy}'Released PVs with Retain policy need manual intervention:
```bash # PV is Released after PVC deletion # Need to reclaim it manually
# Remove claimRef to make PV Available again kubectl patch pv pv-name -p '{"spec":{"claimRef": null}}'
# Or delete and recreate PV kubectl delete pv pv-name kubectl apply -f pv-definition.yaml ```
Verification
After fixing PVC issues:
```bash # Check PVC status kubectl get pvc -n namespace
# Should show Bound status kubectl describe pvc pvc-name -n namespace
# Verify PV is bound kubectl get pv
# Create pod using PVC kubectl apply -f pod-using-pvc.yaml
# Verify pod starts kubectl get pods -n namespace ```
Common PVC Pending Causes
| Cause | Symptoms | Solution |
|---|---|---|
| Missing StorageClass | "storageclass.storage.k8s.io not found" | Create storage class |
| Provisioner failure | Events show provisioning failed | Check CSI driver/provisioner |
| Capacity mismatch | "no PV found" with capacity | Create matching PV or reduce request |
| Access mode mismatch | "access mode not supported" | Use supported access mode |
| Binding mode delay | WaitForFirstConsumer pending | Create pod using PVC |
| Zone mismatch | "zone not available" | Fix topology/topologySpread |
PVC pending issues require checking the entire storage chain: storage class exists, provisioner works, access modes match, and capacity is available. The describe command reveals the specific blocker.