05 - Storage: Volumes, PV, PVC, StorageClasses
Why this matters
Stateful workloads (databases, queues, anything that can't lose data on restart) need storage that outlives the pod. This is one of the trickiest areas to get right in prod.
Read this first — Definitions & Explanations
Volume (generic)
A directory accessible to containers in a Pod. Can be ephemeral (emptyDir) or backed by real storage.
PersistentVolume (PV)
A piece of storage in the cluster provisioned by an admin or dynamically. Cluster-scoped resource representing disk/NFS/cloud volume capacity and access modes.
PersistentVolumeClaim (PVC)
A user/app request for storage (“I need 10Gi ReadWriteOnce”). The control plane binds PVC → PV.
StorageClass
Defines how dynamic volumes are created (provisioner, reclaim policy, parameters). When a PVC asks for a StorageClass, a PV can be auto-provisioned.
Access modes
- ReadWriteOnce (RWO): one node can mount read/write
- ReadOnlyMany (ROX): many nodes read-only
- ReadWriteMany (RWX): many nodes read/write (depends on storage type)
Reclaim policy
What happens to a PV when PVC is deleted: Retain, Delete, or older Recycle. Know this before deleting claims in production.
Dynamic vs static provisioning
- Static: admin pre-creates PVs
- Dynamic: PVC + StorageClass → provisioner creates PV automatically
Official docs (read for detail)
Key Concepts
- Volume: tied to a pod's lifecycle (emptyDir, hostPath, configMap, secret)
- PersistentVolume (PV): cluster-wide storage resource, admin/CSI-provisioned
- PersistentVolumeClaim (PVC): a pod's request for storage — binds to a PV
- StorageClass: template for dynamic provisioning (no admin manually creating PVs)
- CSI (Container Storage Interface): how cloud storage (EBS, EFS, etc.) plugs in
- Access modes: RWO, ROX, RWX
- Reclaim policies: Retain, Delete, Recycle (deprecated)
- Volume binding modes: Immediate vs WaitForFirstConsumer
- StatefulSet +
volumeClaimTemplates— per-replica PVCs
YouTube search terms
- "Kubernetes storage explained PV PVC StorageClass"
- "Kubernetes CSI driver explained"
- "Kubernetes StatefulSet volumeClaimTemplates"
Hands-on lab (on prod-sim)
kubectl get storageclass # minikube ships a default "standard" class
# Dynamic provisioning via PVC
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: test-pvc
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
EOF
kubectl get pvc test-pvc
kubectl get pv # see the PV that got auto-created
# Mount it in a pod, write data, delete pod, remount, prove data persists
kubectl run writer --image=busybox --restart=Never --overrides='
{"spec":{"volumes":[{"name":"data","persistentVolumeClaim":{"claimName":"test-pvc"}}],
"containers":[{"name":"writer","image":"busybox","command":["sh","-c","echo hello > /data/file.txt; sleep 3600"],
"volumeMounts":[{"name":"data","mountPath":"/data"}]}]}}'
kubectl exec writer -- cat /data/file.txt
kubectl delete pod writer --wait
kubectl run reader --image=busybox --restart=Never --overrides='
{"spec":{"volumes":[{"name":"data","persistentVolumeClaim":{"claimName":"test-pvc"}}],
"containers":[{"name":"reader","image":"busybox","command":["cat","/data/file.txt"],
"volumeMounts":[{"name":"data","mountPath":"/data"}]}]}}'
kubectl logs reader # should print "hello" — proves data outlived the pod
# StatefulSet with per-replica storage
kubectl apply -f https://k8s.io/examples/application/web/web.yaml
kubectl get pvc -l app=nginx # one PVC per replica: www-web-0, www-web-1, www-web-2
Notes
(fill in your own words after watching + labbing)