KubernetesXLIX · VolumesVolumes
Persistent volumes introduction — PVs, PVCs, and the binding contract
What you'll learn
- Describe what a PersistentVolume is and what it represents
- Describe what a PersistentVolumeClaim is and how it differs from a PV
- Trace the binding contract between PV and PVC
- Identify the lifecycle states of a PV
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The PersistentVolume (PV) and PersistentVolumeClaim (PVC) are the two halves of Kubernetes’ persistent storage contract. The PV is the actual storage; the PVC is the request; the binding controller matches them. This lesson walks the contract and the lifecycle.
The PV-PVC contract
flowchart LR
A[User: PVC manifest] --> B[API server: PVC persisted]
B --> C[Binding controller]
D[StorageClass provisioner] --> E[PV created]
E --> C
F[Existing PV] --> C
C --> G[PV bound to PVC]
G --> H[Pod mounts PVC]
The contract:
- PVC: a request for storage. The user specifies the size, the access mode, and (optionally) the StorageClass.
- PV: the actual storage. The PV has a capacity, an access mode, a reclaim policy, and a reference to the StorageClass.
- Binding: the binding controller matches a PVC to a PV. The match is by capacity (PV >= PVC), access mode (PV must support at least one of PVC’s modes), and StorageClass (must match).
- Mount: the Pod’s volumes reference the PVC by name; the kubelet mounts the bound PV into the Pod.
What a PersistentVolume is
A PersistentVolume is a cluster-scoped object that represents a piece of storage:
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-001
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: ssd
hostPath:
path: /data/pv-001
The PV’s spec describes:
- capacity: the size of the volume.
- accessModes: the mount modes the volume supports.
- persistentVolumeReclaimPolicy: what happens to the PV when the PVC is deleted.
- storageClassName: the StorageClass the PV belongs to.
- volume source: the actual storage (hostPath, NFS, CSI, etc.).
A PV is cluster-scoped, not namespace-scoped. It is a piece of storage that exists independently of any PVC.
What a PersistentVolumeClaim is
A PersistentVolumeClaim is a namespace-scoped object that represents a request for storage:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data
namespace: production
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Gi
storageClassName: ssd
The PVC’s spec describes:
- accessModes: the mount modes the request needs.
- resources.requests.storage: the minimum capacity.
- storageClassName: the StorageClass to provision from (or to match against existing PVs).
- selector: optional label selector for matching existing PVs.
- volumeName: optional explicit PV to bind to.
A PVC is namespace-scoped. It is a request that lives until it is bound and the bound PV is released.
Lifecycle states
A PV has lifecycle states:
| State | Meaning |
|---|---|
Available | The PV is not yet bound to a PVC; it is available for binding. |
Bound | The PV is bound to a PVC; the PVC references it. |
Released | The PVC was deleted; the PV is awaiting reclamation. |
Failed | The PV failed to be reclaimed (e.g., the provisioner could not delete the underlying storage). |
stateDiagram-v2
[*] --> Available: PV created
Available --> Bound: PVC binds
Bound --> Released: PVC deleted
Released --> Available: reclaim succeeds (Retain: manual)
Released --> [*]: reclaim succeeds (Delete)
Released --> Failed: reclaim fails
Failed --> [*]: manual intervention
The transition depends on the reclaim policy:
- Retain:
Released-> manual cleanup ->Available. - Delete:
Released-> automatic cleanup -> (PV deleted).
Dynamic provisioning
Most production clusters use dynamic provisioning: the PVC’s StorageClass triggers the provisioner to create a PV when the PVC is submitted:
sequenceDiagram
participant U as User
participant API as API server
participant SC as StorageClass
participant CSI as CSI provisioner
participant N as Storage backend
U->>API: create PVC
API->>SC: look up provisioner
SC->>CSI: provision volume
CSI->>N: create backend storage
N->>CSI: volumeHandle
CSI->>API: create PV
API->>U: PVC bound to PV
The user sees only the PVC; the PV is created automatically by the provisioner. The provisioner is the CSI driver.
Static provisioning
For pre-existing volumes (e.g., a manually-created NFS export), the cluster operator creates the PV manually:
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-pv-001
spec:
capacity:
storage: 1Ti
accessModes:
- ReadWriteMany
storageClassName: nfs
nfs:
server: nfs.prod.example.com
path: /exports/data
The PVC is submitted with storageClassName: nfs; the
binding controller matches the PVC to the manually-created
PV.
Quiz
Knowledge check · 4 questions
Q1. A PV is in the `Released` state. What does this mean?
Q2. A PersistentVolume is namespace-scoped.
Q3. Your team submits a PVC with 100 GB request and StorageClass `ssd`. The provisioner creates a PV with 100 GB capacity. Walk through the binding and lifecycle.
Cluster uses dynamic provisioning. PVC submitted with storageClassName: ssd, 100 GB, ReadWriteOnce. The StorageClass's provisioner is ebs.csi.aws.com.
Q4. Explain the difference between dynamic and static provisioning, and when each is appropriate.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- PVC is the user’s request; PV is the implementation. The user writes a PVC; the system provides a PV.
- Dynamic provisioning is the default. The provisioner is the CSI driver.
- Static provisioning is for pre-existing volumes. The operator creates the PV manually.
- PV lifecycle states are diagnostic. Available, Bound, Released, Failed — each tells a story.
ReleasedPVs are a smell. Audit regularly; remediate based on the reclaim policy.