Kubernetes · OpenShift · CSI
Your PersistentVolume is stuck.Don't remove the finalizer.
pvdoctor finds volumes stuck in Terminating, Released, or Failed, works out why, and prints the safe fix — next to the dangerous one you were about to paste from Stack Overflow, and what it would actually destroy.
The hazard
Search for a stuck PV and the first answer is always the same: patch out the finalizer. It works, in the sense that the object goes away.
It also strands the backing disk on your storage array, where it keeps consuming capacity that nothing in the cluster can account for. Do that a few times across a large estate and you have a slow, invisible leak nobody can trace — because the one record tying that disk to a workload was the object you just deleted.
The finalizer is a symptom of a backend condition nothing surfaces to you. pvdoctor finds that condition.
Diagnosis
| Severity | Object | Rule | Summary |
|---|---|---|---|
| CRITICAL | pv/pvc-1a2b3c4d-vsphere | vsphere-orphaned-snapshot | Backing FCD still has CNS snapshots |
| CRITICAL | pv/pvc-4d5e6f70-node-gone | stale-claimref | claimRef points at a deleted PVC |
| WARNING | pv/pvc-2b3c4d5e-detached | stale-claimref | claimRef points at a deleted PVC |
| WARNING | pv/pvc-3c4d5e6f-kasten | backup-finalizer | Kasten K10 finalizer is blocking deletion |
| WARNING | pv/pvc-4d5e6f70-node-gone | dangling-volumeattachment | Attachment left behind by a deleted node |
| WARNING | pv/pvc-5e6f7081-mystery | terminating-no-progress | Terminating with no identified cause |
| INFO | pv/pvc-1a2b3c4d-vsphere | pvc-protection-live-pod | Deletion correctly blocked by running consumers |
Run pvdoctor explain <pv> for the full diagnosis — cause, evidence, ordered fix, and the hazard.
What explain shows you
kubectl patch pv <name> -p '{"metadata":{"finalizers":null}}'
That deletes the Kubernetes object while the backing disk still exists on the storage system. The PV becomes unrecoverable by CSI, the capacity stays allocated, and nothing in the cluster records the orphan.
For vSphere specifically: the stranded VMDK keeps consuming datastore capacity and no longer appears in the CNS container-volume view — that view is populated from Kubernetes metadata, which you have just removed. Finding it later means diffing datastore contents against live volumes by hand.
Resolve the backend condition and the finalizer clears itself. pvdoctor prints the commands; you read them, understand them, and run them. There is no --fix flag, and a unit test fails the build if any rule ever suggests removing a finalizer.
The First Commandment of Storage Thou shalt not strike out the finalizer to hasten thine evening. For the object shall vanish, and the disk shall remain; and it shall drink of thy datastore all its days, and no man shall know its name, nor for what workload it was made.
Nine rules
| Rule | Condition |
|---|---|
| vsphere-orphaned-snapshot | CNS snapshots on the FCD block CSI DeleteVolume |
| csi-deletevolume-failing | Any CSI driver erroring out of DeleteVolume |
| dangling-volumeattachment | Attachment pointing at a node that no longer exists |
| pvc-protection-live-pod | Blocked by pods still mounting the claim — working as intended |
| backup-finalizer | Kasten K10, Velero, Trilio, Stash or Portworx holding the volume |
| stale-claimref | PV reserved for a PVC that was deleted; nothing new can bind |
| retain-released-expected | Released plus reclaimPolicy=Retain is not a bug |
| multi-attach-rwo | RWO volume being pulled toward a second node |
| terminating-no-progress | Stuck past 15 minutes with no recognised cause |
How it behaves
Read-only by construction. No cluster-side component, no operator, nothing to deploy, no --fix. It shells out to your existing kubectl or oc, so your kubeconfig, auth plugins and RBAC are unchanged — and there is no client-go version skew against whatever your cluster happens to be running.
--from reads a directory of JSON dumps instead of a live cluster. Someone with access hands you a bundle; you diagnose it without credentials. Useful for vendors, consultants, and anyone on the wrong side of a change freeze at 3 AM.
mkdir dump
for r in pv pvc pods nodes \
volumeattachments namespaces events; do
kubectl get $r -A -o json > dump/$r.json
done
pvdoctor scan --from dump