flowchart LR
P["Pod"] -- "claimName: data" --> C["PVC data<br/>(namespace dev, 3Gi RWO)"]
C -- "bound" --> V["PV pv-0042<br/>(cluster-scoped)"]
V --> B[("EBS / NFS / CSI")]
- PersistentVolume (PV): a piece of cluster storage, created ahead by an admin (static) or automatically through a StorageClass (dynamic). A PV is cluster-scoped like a Node and lives independently of pods.
- PersistentVolumeClaim (PVC): a user's request for storage, namespaced: size, access mode, optionally a StorageClass or selector. "Pods consume nodes, PVCs consume PVs."
apiVersion: v1
kind: PersistentVolumeClaim
metadata: { name: data, namespace: dev }
spec:
accessModes: [ReadWriteOnce]
resources: { requests: { storage: 3Gi } }
---
# in the Pod
volumes:
- name: data
persistentVolumeClaim: { claimName: data }
Access modes
| Mode | Meaning |
|---|---|
ReadWriteOnce (RWO) |
Read-write by one node (several pods on that node can still use it) |
ReadOnlyMany (ROX) |
Read-only by many nodes |
ReadWriteMany (RWX) |
Read-write by many nodes (NFS, EFS, Azure Files…) |
ReadWriteOncePod (RWOP) |
Read-write by exactly one pod (CSI only) |
volumeMode: Filesystem (default) or Block (a raw block device).
A PVC stays Pending when no PV matches its size/access mode/selector and no StorageClass can provision one. EBS only supports RWO and must be in the same AZ as the node.
| Command | Meaning |
|---|---|
kubectl get pv,pvc -n dev |
STATUS Bound means matched |
kubectl describe pvc data -n dev |
Events while a PVC is Pending |
PV lifecycle
| PV phase | Meaning |
|---|---|
Available |
Free, not bound to a claim |
Bound |
Bound to exactly one PVC |
Released |
Its PVC was deleted; data still there, not reusable automatically |
Failed |
Automatic reclamation failed |
Binding is one-to-one: a 3Gi request may bind to a 10Gi PV if that is the closest match, and the rest is unused. A Released PV with policy Retain keeps the data until an admin cleans it up or rebinds it by removing the old claimRef.
A static PV
apiVersion: v1
kind: PersistentVolume
metadata: { name: pv-nfs-01 }
spec:
capacity: { storage: 10Gi }
accessModes: [ReadWriteMany]
persistentVolumeReclaimPolicy: Retain
nfs: { server: 192.0.2.30, path: /exports/data }
Static PVs suit existing storage you want to expose, such as an NFS share. A PVC can target it with storageClassName: "" and a label selector.
Growing a volume
If the StorageClass has allowVolumeExpansion: true, edit the PVC's resources.requests.storage to a larger value and the CSI driver resizes the disk, often while the pod is running. Volumes can grow but never shrink.
Protection and debugging
Kubernetes adds a kubernetes.io/pvc-protection finalizer: a PVC in use by a pod stays Terminating until the pod is gone, so data is not ripped away from a running app. When a pod waits on storage, kubectl describe pod shows events such as FailedAttachVolume (the disk is still attached to another node or is in another zone) or FailedMount.
Choosing access modes
Most databases need ReadWriteOnce block storage. Shared uploads or content used by several replicas need ReadWriteMany file storage such as NFS, Amazon EFS, or Azure Files. Using RWO for a Deployment with several replicas across nodes makes extra pods hang in ContainerCreating.