Storage: Volumes, PVCs & CSI
Disks that follow, not forget
Kubernetes abstracts storage with CSI: StorageClasses provision PVs on demand via PVCs; pods mount PVs by claim. emptyDir/hostPath cover first-party ephemeral needs; persistent classes map to EBS/gcePersistentDisk/azureDisk or network filesystems for shared reads.
What you will learn
- Explain StorageClass → PV provisioning → PVC → pod mount
- Differentiate access modes: RWO, RWX, ReadOnlyMany
- Choose block vs file vs object reach from the cluster
You declare a PVC (size + class + access mode). The provisioner creates a PV (an EBS/PD/disk volume), claim binds, pod mounts. CSI makes storage backends pluggable: EBS, EFS, GCE PD, azureDisk and more.
What is this?
StorageClass: parameters (provisioner, type/encryption/IOPS), reclaimPolicy (Delete/Retain), volumeBindingMode (WaitForFirstConsumer), allowVolumeExpansion. PVC: spec(size, accessModes[], storageClassName). Access modes: RWO (single node R/W), RWM (multinode R/W), ROM/ReadOnlyMany. PV types: local (no provisioning), hostPath (node FS), generic CSI, CSI storage drivers (aws-ebs, efs, gce-pd, azure-disk, csi-driver-nfs). Persistent volume claims also used by StatefulSets per-replica. Ephemeral: emptyDir (pod-scoped), volumeFrom + projected. SubPath/MountOptions/volumeAttributes define depth of mapping.
Why do you need it?
- PVC/CSI decouple 'I need storage' from 'which storage vendor' — portability across clouds.
- WaitForFirstConsumer + topology matches disk to where the pod lands (latency).
- StorageClasses encode environment policy (fast SSD prod vs cheap staging) centrally.
- Stateful storage following a rescheduled pod is the DB-on-K8s superpower.
Mental model
A restaurant ordering 'one prep room this stall' from the mall maintenance
PVC → PV
The kitchen says 'I need a prep room, 12m², on our floor' (PVC). The maintenance office (provisioner) assigns an actual room (PV) that matches — and claws it back when we leave (reclaim).
How it works
- Pod references PVC in volumes/volumeMounts.
- Controller sees unbound PVC → matches a storage class → invokes provisioner → PV created.
- Claim binds (PVC ↔ PV 1:1); scheduler pins to a node respecting topology (WaitForFirstConsumer).
- kubelet + CSI mount driver attach + mount; container FS sees the volume.
- On pod deletion, PVC remains; on PVC deletion, reclaimPolicy Delete tears down the cloud disk.
Storage provisioning flow.
Examples
Claim + deploy a stateful WP-style pod
kind: PersistentVolumeClaimapiVersion: v1metadata: { name: www-data }spec: accessModes: [ReadWriteOnce] storageClassName: standard resources: { requests: { storage: 10Gi } }# pod: volumes: [{name: data, persistentVolumeClaim: { claimName: www-data }}]The pod just names the claim; the platform resolves capacity, type and node affinity.
In production
- PostgreSQL/Prometheus on per-pod PVCs with snapshots scheduled via CSI.
- EFS/NFS RWX class for shared uploads behind multiple replicas.
- Temporary build/job scratch on emptyDir with sizeLimit to stop disk hogging.
Best practices
- Prefer WaitForFirstConsumer classes for low-latency disks.
- Set reclaimPolicy=Retain for anything you might need to salvage (pre-prod fashion was surprise).
- Use PVC-based state even in v1 workloads → swap to larger classes without surgical yaml.
- Snapshot DB volumes using CSI between upgrades; test restore into a scratch cluster.
- Keep StorageClass parameters versioned alongside IaC.
Common mistakes
- RWX backing Postgres data → corruption (needs RWO).
- emptyDir used as DB persistence then lost on pod recreate.
- hostPath leaks node state into pod assumptions; prefer PV/CSI.
- Delete-scoped PVCs: an rm of a namespace nukes production data without Retain.
Debugging tips
- PVC stays Pending → storage class missing or volumeBindingMode+node affinity mismatch; describe pvc/pv.
- Pod stuck MountVolume → CSI driver pods healthy? disk attach quota? driver log.
- RWO contention → second node can't mount; decide multi-writer carefully.
- Capacity full on PV → expand claim in-place only if allowVolumeExpansion + filesystem supports grow.
Interview checkpoint
Quick quiz
ReadWriteOnce means:
reclaimPolicy=Delete on the StorageClass destroys: