6.10 Storage Failures: PVC Pending, Mount Failures & Multi-Attach Errors
Key Takeaways
- PersistentVolumeClaims (PVCs) remain in the 'Pending' phase due to: missing or non-default StorageClasses, insufficient available PersistentVolume (PV) capacity, accessModes mismatches (e.g., ReadWriteMany vs ReadWriteOnce), or label/selector conflicts.
- When 'volumeBindingMode: WaitForFirstConsumer' is configured on a StorageClass, dynamic PV provisioning and PVC binding are intentionally delayed until a pod referencing the PVC is scheduled to a specific node.
- Pods get stuck in 'ContainerCreating' with 'Multi-Attach error for volume' when a ReadWriteOnce (RWO) volume is still locked by a detached or crashed node that has not completed unmount/detach operations.
- Volume expansion requires allowVolumeExpansion on the StorageClass; online filesystem growth depends on CSI and filesystem support, and FileSystemResizePending may require restarting a consuming Pod.
- Before reusing a Retain-policy Released PV, secure or scrub its data for the intended claimant, then clear spec.claimRef and constrain the new binding deliberately.
6.10 Storage Failures: PVC Pending, Mount Failures & Multi-Attach Errors
Managing persistent state in a distributed container orchestration system involves coordinating the Kubernetes storage control loops (PV controller, Attach/Detach controller, and Volume Manager) with third-party Container Storage Interface (CSI) drivers, cloud storage APIs, and host filesystem mount points.
Storage misconfigurations cause pods to hang in Pending or ContainerCreating. Diagnosing storage problems requires understanding the binding lifecycle, CSI plugin communication, and reclaim policies.
1. Storage Architecture & Binding Lifecycle
+-----------------------------------------------------------------------------------------+
| STORAGE BINDING & ATTACHMENT PIPELINE |
| |
| 1. DEVELOPER CREATES PVC |
| apiVersion: v1, kind: PersistentVolumeClaim (Requests 10Gi, ReadWriteOnce) |
| | |
| v |
| 2. PV CONTROLLER ATTEMPTS BINDING |
| - Static Provisioning: Matches existing PV with sufficient capacity, matching |
| accessModes, and matching storageClassName. |
| - Dynamic Provisioning: StorageClass invokes CSI External Provisioner to create PV. |
| | |
| v |
| 3. PVC STATUS: BOUND (PV status: Bound) |
| | |
| v |
| 4. POD REFERENCING PVC IS SCHEDULED |
| - Attach/Detach Controller calls CSI Driver -> Attaches block device to Node. |
| - Kubelet Volume Manager mounts filesystem to /var/lib/kubelet/pods/<uid>/volumes. |
| - Container launches with mounted volume. |
+-----------------------------------------------------------------------------------------+
2. Troubleshooting PVC: Pending State
When a PersistentVolumeClaim remains in Pending, execute kubectl describe pvc <pvc-name> to inspect controller events:
kubectl describe pvc my-claim
High-Frequency PVC Pending Causes & Fixes:
| Failure Message in Events | Root Cause | Remediation |
|---|---|---|
no volume plugin matched name or storageclass not found | The PVC specifies a storageClassName that does not exist in the cluster (kubectl get sc). | Create the missing StorageClass or fix the typo in pvc.spec.storageClassName. |
waiting for a volume to be created, either by external provisioner or manually | No StorageClass was specified and no default StorageClass is configured in the cluster. | Mark a StorageClass as default: kubectl patch sc <sc-name> -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'. |
cannot satisfy accessModes [ReadWriteMany] | Static PVs exist, but none provide the requested ReadWriteMany (RWX) access mode (most cloud block stores only support ReadWriteOnce). | Change PVC request to ReadWriteOnce or provision an NFS/Ceph/EFS PV supporting RWX. |
insufficient capacity: requested 20Gi, available 10Gi | Static PV exists but its capacity is smaller than the requested size in the PVC. | Provision a larger PV or decrease the PVC request. |
waiting for first consumer to be created before binding | NORMAL BEHAVIOR: The StorageClass has volumeBindingMode: WaitForFirstConsumer. | The PVC will remain Pending until a Pod referencing this PVC is created and scheduled. |
# Example of Default StorageClass Annotation
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard-ssd
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
3. Pod Stuck in ContainerCreating: Mount & Multi-Attach Errors
When a PVC is Bound, but the referencing pod remains stuck in ContainerCreating, inspect kubectl describe pod <pod-name>:
Failure Mode 1: Multi-Attach error for volume
Events:
Warning FailedAttachVolume 15s attachdetach-controller Multi-Attach error for volume "pvc-9a8b7c": Volume is already exclusively attached to one node and cannot be attached to another
- Root Cause: A
ReadWriteOnce(RWO) cloud block volume (e.g., AWS EBS, GPD) can only be attached to a single virtual machine node at a time. If the previous node crashed or was abruptly partitioned without completing the detach operation, the cloud provider's control plane locks the volume to the dead node while the scheduler attempts to run the replacement pod on a new node. - Remediation:
- Verify the old node status. If dead, delete the old pod with
kubectl delete pod <old-pod> --force --grace-period=0. - Inspect VolumeAttachment objects:
kubectl get volumeattachments. - If the old node is conclusively gone, follow the CSI driver and storage-provider force-detach procedure. Deleting a VolumeAttachment object is not a generic cloud detach and can risk concurrent attachment or corruption; do it only when the provider runbook or task explicitly calls for it.
- Verify the old node status. If dead, delete the old pod with
Failure Mode 2: CSI Node Driver Pod Unhealthy
Events:
Warning FailedMount 10s kubelet MountVolume.SetUp failed for volume "pvc-xxxx" : rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing /var/lib/kubelet/plugins_registry/csi.sock: connect: no such file or directory"
- Root Cause: The CSI node plugin DaemonSet pod on that specific worker node has crashed or restarted, breaking the local gRPC UNIX domain socket.
- Remediation: Inspect CSI DaemonSet health:
kubectl get pods -n kube-system -l app=csi-driverand check logs.
4. Volume Expansion Failures (FileSystemResizePending)
To increase the size of an existing PVC:
- Ensure the underlying StorageClass has
allowVolumeExpansion: true:apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: expandable-sc allowVolumeExpansion: true provisioner: ebs.csi.aws.com - Edit the PVC:
kubectl edit pvc data-claimand increase.spec.resources.requests.storagefrom10Gito20Gi. - Symptom: The PVC status changes to
FileSystemResizePending.- Explanation: The controller-side volume may already be larger while node-side filesystem expansion is incomplete. Many CSI/filesystem combinations support expansion while the Pod is running; if this combination requires offline expansion, restart the consuming Pod and inspect CSI and kubelet events.
5. Recovering Data from Released PersistentVolumes
When a PVC is deleted, the bound PV's fate is governed by its persistentVolumeReclaimPolicy:
Delete: Kubernetes removes the PV and asks the provisioner to delete the backing asset; completion is asynchronous and provider-dependent.Retain: The PV is preserved, transitioning to statusReleased.
+-----------------------------------------------------------------------------------------+
| RECLAIMING A 'RELEASED' PERSISTENTVOLUME |
| |
| 1. PVC DELETED ---> PV status transitions to 'Released' |
| (PV contains data, but cannot be bound by any new PVC because |
| it still holds a pointer in .spec.claimRef to the deleted PVC). |
| | |
| v |
| 2. SECURE OR SCRUB RETAINED DATA FOR THE INTENDED NEW CLAIMANT
| | |
| v |
| 3. STRIP CLAIMREF POINTER |
| $ kubectl patch pv pv-data -p '{"spec":{"claimRef": null}}' |
| | |
| v |
| 4. PV STATUS TRANSITIONS TO 'Available' |
| New PVCs can now successfully bind to this PV and access retained data. |
+-----------------------------------------------------------------------------------------+
A developer submits a PersistentVolumeClaim requesting 50Gi with storageClassName: fast-storage. The PVC remains in the Pending state. The administrator runs kubectl describe pvc and sees the event: waiting for a volume to be created, either by external provisioner or manually. Running kubectl get sc reveals no StorageClass named fast-storage exists. What must be done to resolve this issue?
A stateful pod db-master-0 is rescheduled to node-2 after node-1 suffered a power outage. The pod remains stuck in ContainerCreating for over 10 minutes with the event: Multi-Attach error for volume "pvc-1234": Volume is already exclusively attached to one node and cannot be attached to another. What is the technical cause of this error?
A Retain-policy PV is Released. After the administrator secures or scrubs its retained data for the intended new claimant, which command clears the old PVC reservation?