5.2 PersistentVolumes (PV) & PersistentVolumeClaims (PVC) Lifecycle
Key Takeaways
PersistentVolumes (PVs) are cluster-scoped storage resources provisioned statically by administrators or dynamically by CSI drivers, while PersistentVolumeClaims (PVCs) are namespace-scoped user requests for storage.
The PV-PVC lifecycle moves through four sequential stages: Provisioning (Static vs. Dynamic) -> Binding -> Using -> Reclaiming (Retain, Delete, Recycle).
A PV progresses through four operational states: Available (unbound), Bound (exclusively linked to a PVC), Released (PVC deleted, storage retained), and Failed (automated reclamation error).
Binding is a strict 1-to-1 two-way relationship evaluated by persistentvolume-controller based on capacity (PV >= PVC), accessModes, volumeMode, storageClassName, and label selectors.
volumeMode determines whether storage is presented as a formatted filesystem (volumeMode: Filesystem mounted via volumeMounts) or a raw block device (volumeMode: Block mapped via volumeDevices).
5.2 PersistentVolumes (PV) & PersistentVolumeClaims (PVC) Lifecycle
Managing persistent state in a containerized, distributed orchestration platform requires abstracting the underlying storage implementation details from application developers. In traditional on-premise or cloud environments, configuring storage arrays (such as iSCSI LUNs, NFS shares, AWS EBS volumes, or Ceph RBD pools) requires infrastructure-level privileges and vendor-specific configuration. Exposing these low-level parameters directly inside application Pod manifests breaks workload portability and violates the principle of least privilege.
Kubernetes solves this decoupling challenge through two core API primitives: the PersistentVolume (PV) and the PersistentVolumeClaim (PVC). This architectural separation enforces a strict division of responsibilities: cluster administrators manage the provisioned storage capacity (PVs), while application developers consume storage via declarative requests (PVCs) without needing knowledge of the backing storage fabric.
1. The Storage Abstraction Architecture & Persona Separation
+-----------------------------------------------------------------------------------------+
| CLUSTER SCOPE |
| |
| +-----------------------------+ +-----------------------------------+ |
| | STORAGE ADMINISTRATOR | | PersistentVolume (PV) | |
| | - Provisions SAN/NFS/Cloud | ------------> | - Capacity: 50Gi | |
| | - Defines Access Modes | | - AccessMode: ReadWriteOnce | |
| | - Reclaim Policy: Retain | | - ReclaimPolicy: Retain | |
| +-----------------------------+ +-----------------+-----------------+ |
| | |
|====================================================================|====================|
| NAMESPACE SCOPE: production | (1-to-1 Binding) |
| v |
| +-----------------------------+ +-----------------+-----------------+ |
| | APPLICATION DEVELOPER | | PersistentVolumeClaim (PVC) | |
| | - Requests: 30Gi RWO | ------------> | - Request: 30Gi | |
| | - References StorageClass | | - AccessMode: ReadWriteOnce | |
| +-----------------------------+ +-----------------+-----------------+ |
| | |
| | spec.volumes.pvc |
| v |
| +-----------------+-----------------+ |
| | WORKLOAD POD | |
| | Mounts to /var/lib/postgresql | |
| +-----------------------------------+ |
+-----------------------------------------------------------------------------------------+
Architectural Distinction: PV vs. PVC
| Attribute | PersistentVolume (PV) | PersistentVolumeClaim (PVC) |
|---|---|---|
| API Scope | Cluster-scoped (kubectl get pv) | Namespace-scoped (kubectl get pvc -n <ns>) |
| Target Persona | Infrastructure / Cluster Administrator | Application Developer / Tenant |
| Core Purpose | Represents actual physical/virtual storage | Represents an abstract storage resource request |
| Binding Cardinality | Bound to exactly one PVC (spec.claimRef) | Bound to exactly one PV (spec.volumeName) |
| Lifecycle Dependency | Independent of any Pod or Namespace | Bound to user lifecycle; triggers PV reclamation |
2. Complete 4-Phase PV & PVC Lifecycle
The interaction between PersistentVolumes and PersistentVolumeClaims is orchestrated by the control plane's persistentvolume-controller through four sequential phases:
1. Provisioning 2. Binding 3. Using 4. Reclaiming
Phase 1: Provisioning (Static vs. Dynamic)
- Static Provisioning: A cluster administrator manually provisions physical storage devices (e.g., creating an NFS export or Ceph volume) and submits declarative
PersistentVolumemanifests to the Kubernetes API server. - Dynamic Provisioning: When no pre-existing static PV matches a user's PVC, the cluster automatically triggers a Container Storage Interface (CSI) provisioner via a
StorageClassto create the backend storage asset and instantiate a corresponding PV object on the fly.
Phase 2: Binding
The persistentvolume-controller continuously watches for unbound PVCs and executes an evaluation algorithm to find the optimal matching PV.
- When a match is found, the controller executes an exclusive two-way mutual binding:
- In the PV: Sets
spec.claimRefto the PVC's UID, name, and namespace. - In the PVC: Sets
spec.volumeNameto the PV name and transitions status toBound.
- In the PV: Sets
- If no matching PV exists and dynamic provisioning is disabled, the PVC remains indefinitely in
Pendingstatus.
Phase 3: Using
The application developer references the PVC in a Pod manifest under spec.volumes[*].persistentVolumeClaim.claimName.
- The scheduler places the Pod on an eligible node.
- The local
kubeletand CSI Node Plugin attach the storage device, format it (if filesystem mode), and bind-mount it into the container's designatedmountPath.
Phase 4: Reclaiming
When the application is decommissioned and the user deletes the PVC, the bound PV enters the reclamation phase dictated by its persistentVolumeReclaimPolicy:
Retain: PV status transitions toReleased. The underlying data on disk is preserved. The PV cannot be claimed by any other PVC until an administrator manually clearsspec.claimRef.Delete: The PV object is automatically deleted from Kubernetes, and the CSI driver calls the underlying storage provider API to destroy the physical storage volume.Recycle(Deprecated): Runs a basic scrubbing command (rm -rf /mount/*) and returns the PV toAvailable.
3. PV Operational Status State Transitions
[ Admin Manifest / CSI Provisioning ]
|
v
+------------------+
| AVAILABLE | <-------------------------+
+--------+---------+ |
| |
| PVC matches criteria | Admin cleans data
v | & patches claimRef
+------------------+ |
| BOUND | |
+--------+---------+ |
| |
| User deletes PVC |
v |
+------------------+ Manual Reclaim |
| RELEASED | --------------------------+
+--------+---------+
|
| Automated deletion error (CSI)
v
+------------------+
| FAILED |
+------------------+
| PV Status | Technical Definition & System State |
|---|---|
Available | The PV is free, healthy, and ready to be claimed by any matching PVC in any namespace. |
Bound | The PV is exclusively locked and bound to a specific PVC. No other claim can bind to it. |
Released | The associated PVC has been deleted, but the physical resource has not yet been reclaimed. Data is intact. |
Failed | The automated reclamation or deletion process failed (e.g., cloud API credentials expired or disk locked). |
4. The 5-Point PVC-to-PV Binding Evaluation Algorithm
For persistentvolume-controller to bind an incoming PVC to a static PV, all five of the following evaluation criteria must pass simultaneously:
- Storage Capacity: The PV capacity must be greater than or equal to the PVC requested storage (
pv.spec.capacity.storage >= pvc.spec.resources.requests.storage). (Note: If a PVC requests 10Gi and the smallest available PV is 100Gi, Kubernetes will bind it, resulting in 90Gi of unallocated capacity). - Access Modes: The PV must satisfy all access modes declared in
pvc.spec.accessModes(e.g.,ReadWriteOnce,ReadWriteMany). - Volume Mode:
spec.volumeModemust match identically (FilesystemwithFilesystem, orBlockwithBlock). - StorageClass:
pvc.spec.storageClassNamemust matchpv.spec.storageClassName. If a PVC specifiesstorageClassName: "", it will only bind to PVs that explicitly declarestorageClassName: ""or omit the field. - Label Selectors: If the PVC specifies
spec.selector.matchLabelsormatchExpressions, the PV'smetadata.labelsmust satisfy the selector.
5. Declarative Manifests: Filesystem vs. Raw Block Storage
Static PersistentVolume (Filesystem Mode)
apiVersion: v1
kind: PersistentVolume
metadata:
name: enterprise-nfs-pv
labels:
environment: production
tier: db
spec:
capacity:
storage: 50Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
nfs:
server: 10.96.15.200
path: /srv/nfs/pgdata
PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-data-pvc
namespace: production
spec:
accessModes:
- ReadWriteOnce
volumeMode: Filesystem
resources:
requests:
storage: 50Gi
storageClassName: manual
selector:
matchLabels:
environment: production
tier: db
Raw Block Volume (volumeMode: Block)
High-throughput databases (e.g., Cassandra, RocksDB, or custom key-value engines) often bypass the Linux filesystem layer to eliminate filesystem journaling overhead:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: raw-block-pvc
namespace: production
spec:
accessModes:
- ReadWriteOnce
volumeMode: Block
resources:
requests:
storage: 100Gi
storageClassName: manual
---
apiVersion: v1
kind: Pod
metadata:
name: raw-db-pod
namespace: production
spec:
containers:
- name: db-engine
image: custom-db:v2.4
volumeDevices:
- name: raw-storage-device
devicePath: /dev/xvdf
volumes:
- name: raw-storage-device
persistentVolumeClaim:
claimName: raw-block-pvc
Note
When consuming a raw block volume (volumeMode: Block), you must declare volumeDevices with devicePath instead of volumeMounts with mountPath.
6. Verification & Troubleshooting CLI Playbook
# 1. List all PVs cluster-wide and check claim references
kubectl get pv -o wide
# 2. List PVCs in a target namespace
kubectl get pvc -n production
# 3. Diagnose why a PVC is stuck in Pending status
kubectl describe pvc postgres-data-pvc -n production
# 4. Check if PV claimRef is locking a Released volume
kubectl get pv enterprise-nfs-pv -o jsonpath='{.spec.claimRef}'
A PersistentVolume provisioned with persistentVolumeReclaimPolicy: Retain is bound to a PVC named data-pvc in the finance namespace. A developer deletes data-pvc. What will be the resulting status of the PV, and can another PVC immediately bind to it?
The PV transitions to Available status and is immediately eligible for binding by other PVCs.
The PV transitions to Failed status and requires an operating system reboot to recover.
The PV is permanently deleted from the cluster along with its underlying physical data.
The PV transitions to Released status and cannot be bound by any new claim until an administrator manually clears spec.claimRef.
A developer submits a PVC requesting 20Gi of storage with accessModes: [ReadWriteMany] and storageClassName: manual. The cluster has an available static PV with capacity: 100Gi, accessModes: [ReadWriteOnce], and storageClassName: manual. Why does the PVC remain stuck in Pending status?
The PV capacity (100Gi) is too large for the 20Gi requested by the PVC.
The access modes do not match: the PVC requires ReadWriteMany, but the available PV only supports ReadWriteOnce.
Static PersistentVolumes cannot be bound to claims requesting less than 50Gi of storage.
The PVC did not declare an explicit volumeMode attribute.
An administrator is configuring a low-latency Cassandra database that requires raw block storage access (volumeMode: Block). How must the container inside the Pod manifest reference this volume?
Under volumeMounts using mountPath: /dev/block.
Under rawMounts using targetPath: /dev/xvda.
Under volumeDevices using devicePath: /dev/xvda.
Under blockMounts using storagePath: /dev/xvda.
Sections you finish are checked off in the contents.