PersistentVolumeClaims stuck without a volume
What does ZopNight detect here?
A PersistentVolumeClaim in Pending state has requested storage that was never provisioned, so any pod mounting it cannot start. ZopNight surfaces these as orphans. There are 4 usual causes, and the kubectl describe output carries the provisioner error that names which one applies.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-1740 · RC-1840 · RC-1940 |
| Category | orphan |
| Severity | medium |
| Metric | none — pure configuration read |
| Source | internal/rules/k8s/pvc_unbound.go |
Where it applies
A pending claim blocks a pod, silently
A pod mounting an unbound PVC does not fail. It stays Pending indefinitely, because the
scheduler cannot place a pod whose volume does not exist yet.
That failure mode is quiet: no crash loop, no restart count climbing, no error in the container log. The container never started. Teams often find these only when someone asks why a deployment has been at zero ready replicas since last Tuesday.
Why claims stay unbound
No default StorageClass, or a storageClassName naming one that does not exist in this
cluster. Extremely common after moving a manifest between clusters.
Zone mismatch. With WaitForFirstConsumer binding, the volume is created in the zone of the
node the pod lands on. If node affinity forces the pod somewhere the storage class cannot
provision, neither side resolves.
Quota exhausted. A namespace ResourceQuota limiting requests.storage or
persistentvolumeclaims blocks new claims once reached, and the message lives on the PVC rather
than anywhere obvious.
Capacity unavailable in the requested zone for that volume type.
The cost angle, such as it is
An unbound PVC provisions nothing, so it costs nothing directly. This is a reliability finding wearing an orphan label.
What it can indicate is money: a namespace full of pending claims usually means a workload was half-migrated, and the volumes it did successfully create elsewhere may now be orphaned and billing.
Describing a Pending PVC for the provisioner error
kubectl get pvc -A --field-selector status.phase=Pendingkubectl describe pvc <name> -n <namespace> | tail -20The describe output carries the provisioner’s actual error, which is where the real answer
lives. The phase alone tells you nothing about the cause.