KubernetesL · PersistentVolumes and ClaimsPersistentVolumes and Claims
PV-PVC binding — how Kubernetes matches storage requests to volumes
What you'll learn
- Describe the binding controller's matching algorithm
- Distinguish dynamic from static binding
- Identify the edge cases that leave a PVC Pending
- Apply selectors and volumeName for explicit binding
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
PV-PVC binding is the controller in the control plane that matches storage requests to actual volumes. This lesson walks the matching algorithm, the edge cases that leave PVCs Pending, and the production patterns for explicit binding.
The binding algorithm
The binding controller runs in the kube-controller-manager. For each unbound PVC, it:
- Looks for an existing PV that matches the PVC’s criteria.
- If no PV matches and the PVC has a StorageClass, calls the provisioner to create a PV.
- If no PV is created (no StorageClass, provisioner
fails), the PVC remains
Pending.
The matching criteria:
- Capacity: PV’s capacity >= PVC’s request.
- Access modes: PV must support at least one of PVC’s requested modes.
- StorageClass: PV’s storageClassName == PVC’s storageClassName (or both are unset).
- Selector: if PVC has a selector, PV’s labels must match.
- volumeName: if PVC has a volumeName, that exact PV must match.
The first PV that satisfies all criteria is bound.
Dynamic vs static binding
Dynamic binding
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: submit PVC with storageClassName: ssd
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 new PV
The user submits a PVC with a StorageClass; the provisioner creates the PV; the binding is automatic.
Static binding
For pre-existing volumes, the operator creates the PV manually:
apiVersion: v1
kind: PersistentVolume
metadata:
name: manual-pv
labels:
workload: legacy
spec:
capacity:
storage: 500Gi
accessModes:
- ReadWriteMany
storageClassName: legacy
nfs:
server: nfs.prod.example.com
path: /exports/legacy
The user submits a PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: legacy-data
spec:
accessModes: ["ReadWriteMany"]
storageClassName: legacy
selector:
matchLabels:
workload: legacy
resources:
requests:
storage: 100Gi
The PVC’s selector matches the PV’s labels; the binding is static.
The selector field
The PVC’s selector matches PVs by labels:
selector:
matchLabels:
workload: legacy
matchExpressions:
- key: environment
operator: In
values: ["production"]
A PVC with a selector does not match PVs whose labels do not match. This is useful for:
- Pre-allocating PVs for specific workloads.
- Restricting which PVs a PVC can bind to.
- Avoiding accidental binding to unrelated PVs.
The volumeName field
The PVC’s volumeName binds to a specific PV by name:
spec:
volumeName: my-pv
The binding controller looks up the PV by name and binds if it matches. If the PV does not exist or does not match, the PVC is Pending.
volumeName is used for:
- Recovering a released PV (binding to a specific PV).
- Pre-allocating a PV for a specific workload.
- Reserving a PV before it is needed.
Edge cases that leave PVCs Pending
A PVC remains Pending when:
- No matching PV exists and the StorageClass has no provisioner (or the provisioner is down).
- The StorageClass does not match: the PVC asks for
ssd, onlystandardPVs are available. - The access mode is not supported: the PVC asks for RWX, only RWO PVs are available.
- The capacity is insufficient: all available PVs are smaller than the request.
- The selector matches no PV: the PVC has a selector that no available PV matches.
- The volumeName points to a non-existent or non-matching PV: explicit binding fails.
# Substitute your own values before running:
PVC=data-postgres-0
NS=production
# Diagnose a Pending PVC
kubectl describe pvc "$PVC" -n "$NS"
# Events show the reason:
# "no persistent volumes available for this claim and no storage class is set"
# "persistentvolumeclaim requires matching volumeMode, accessMode, and storageClassName"
Quiz
Knowledge check · 4 questions
Q1. A PVC is submitted with `storageClassName: ssd`. The cluster has only `standard` StorageClass PVs. What happens?
Q2. A PVC with a selector that matches no available PV remains Pending until a matching PV is created.
Q3. A team submits a PVC requesting 100 GB on the `ssd` StorageClass. The PVC is Pending. Walk through the diagnostic.
PVC: storageClassName: ssd, 100 GB, ReadWriteOnce. Status: Pending. Events show "waiting for a volume to be created" or "no persistent volumes available".
Q4. Explain the difference between a PVC selector and a PVC volumeName, and when each is appropriate.
Passing score: 75%. Answers are checked in this browser.
Production discipline
- The StorageClass must match. A PVC on
ssddoes not bind to astandardPV. - The selector is for static binding. It does not trigger provisioning.
- The volumeName is for explicit binding. Use it for recovery and reservation.
- Pending PVCs are diagnostic events. Always check
kubectl describe pvcfor the reason. - The provisioner is the bottleneck. A slow provisioner leaves PVCs Pending. Monitor provisioner latency.