PersistentVolumes, Claims, and StorageClasses
The idea in one sentence
Section titled “The idea in one sentence”A PersistentVolumeClaim is a request for storage that a Pod mounts, and it binds to a PersistentVolume — a piece of cluster storage that can outlive the Pod and follow it across nodes.
The gap emptyDir and hostPath cannot close
Section titled “The gap emptyDir and hostPath cannot close”emptyDir dies with the Pod, and hostPath ties data to one specific node — neither survives a Pod being rescheduled onto different hardware, which is exactly what the scheduler is free to do at any time. Real stateful workloads (databases, message queues, anything with data that matters) need storage that exists independently of any single Pod or node, and that a rescheduled Pod can reattach to wherever it lands.
PersistentVolume and PersistentVolumeClaim
Section titled “PersistentVolume and PersistentVolumeClaim”A PersistentVolume (PV) is a cluster-level storage resource — conceptually similar to how a Node represents compute capacity, a PV represents a chunk of storage capacity. A cluster administrator can provision PVs statically ahead of time, or they can be created dynamically (more on that below).
A PersistentVolumeClaim (PVC) is a request made by a user or application: “I need this much storage, with this access mode.” Kubernetes binds the PVC to a PV that satisfies the request. Crucially, Pods reference the PVC, never the PV directly — the Pod does not need to know or care which physical PV it ended up bound to.
apiVersion: v1kind: PersistentVolumemetadata: name: pv-manual-10gispec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: manual hostPath: path: /mnt/dataapiVersion: v1kind: PersistentVolumeClaimmetadata: name: data-claimspec: accessModes: - ReadWriteOnce resources: requests: storage: 10Gi storageClassName: manualapiVersion: v1kind: Podmetadata: name: dbspec: containers: - name: postgres image: postgres:16 volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumes: - name: data persistentVolumeClaim: claimName: data-claimAccess modes
Section titled “Access modes”A PV declares which access modes it supports, and a PVC requests one it needs:
ReadWriteOnce(RWO) — the volume can be mounted read-write, but only by Pods running on a single node at a time.ReadOnlyMany(ROX) — the volume can be mounted read-only by many nodes at once.ReadWriteMany(RWX) — the volume can be mounted read-write by many nodes at once (only some storage backends support this).ReadWriteOncePod(RWOP) — a newer, stricter mode: the volume is restricted to a single Pod across the whole cluster, not just a single node. PlainReadWriteOncestill allows multiple Pods to share the volume as long as they land on the same node;ReadWriteOncePodcloses that gap when you need a true single-writer guarantee.
Dynamic provisioning with a StorageClass
Section titled “Dynamic provisioning with a StorageClass”Hand-provisioning PVs does not scale. A StorageClass describes a class of storage and a provisioner capable of creating it on demand — when a PVC references a StorageClass instead of an existing PV, a CSI (Container Storage Interface) driver automatically provisions a matching PV for it. No administrator has to pre-create anything.
apiVersion: storage.k8s.io/v1kind: StorageClassmetadata: name: fast-ssdprovisioner: ebs.csi.aws.comparameters: type: gp3reclaimPolicy: DeletevolumeBindingMode: WaitForFirstConsumerapiVersion: v1kind: PersistentVolumeClaimmetadata: name: dynamic-claimspec: accessModes: - ReadWriteOnce storageClassName: fast-ssd resources: requests: storage: 20Gi# Watch a PVC bind to a dynamically provisioned PVkubectl get pvc dynamic-claim -wReclaim policy: what happens after the PVC is gone
Section titled “Reclaim policy: what happens after the PVC is gone”The reclaim policy decides the fate of the underlying storage once its PVC is deleted:
Delete— the PV and its underlying storage (the actual disk) are deleted along with the PVC. This is the default for most dynamically provisioned StorageClasses.Retain— the PV and its data are kept around after the PVC is deleted, so an administrator can manually recover or clean up the data before the underlying storage is released.
flowchart LR
pod["Pod"] -->|mounts| pvc["PVC: dynamic-claim"]
pvc -->|references| sc["StorageClass: fast-ssd"]
sc -->|CSI driver provisions| pv["New PersistentVolume"]
pv --> disk[("Underlying disk, e.g. an EBS volume")]