How it works
The explanation, with examples you can run.
Storage: claims, volumes and classes
- A PersistentVolumeClaim (PVC) is a request: "20 GiB of
fast-ssd, mountable by one pod". - A StorageClass describes how to provision such storage (a cloud disk type, a CSI driver, parameters, reclaim policy).
- A PersistentVolume (PV) is the actual disk, usually created on demand by the class's provisioner and bound to the claim.
A pod mounts the claim by name. If the pod is deleted, the claim and its data stay. Access modes matter: most block storage is ReadWriteOnce (one node at a time), and the Kubernetes docs recommend ReadWriteOncePod (one pod) for single-writer workloads.
A StatefulSet
apiVersion: v1kind: Servicemetadata: name: dbspec: clusterIP: None # headless: DNS names for each pod, no virtual IP selector: app: db ports: - port: 5432---apiVersion: apps/v1kind: StatefulSetmetadata: name: dbspec: serviceName: db replicas: 3 selector: matchLabels: app: db persistentVolumeClaimRetentionPolicy: whenDeleted: Retain whenScaled: Retain template: metadata: labels: app: db spec: containers: - name: postgres image: postgres:17 ports: - containerPort: 5432 volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOncePod"] storageClassName: fast-ssd resources: requests: storage: 20GiThis produces pods db-0, db-1 and db-2, claims data-db-0 to data-db-2, and DNS names such as db-0.db.shop.svc.cluster.local. By default pods are created one at a time in order (each must be ready before the next starts) and removed in reverse order; podManagementPolicy: Parallel relaxes that. Rolling updates also go from the highest ordinal down. The headless Service has to exist; you create it yourself.
What StatefulSets do not do
A StatefulSet gives identity and storage, not database expertise. It does not know which replica is the primary, how to replicate data, how to fail over, or how to back up. Running Postgres with three StatefulSet replicas gives you three unrelated databases unless the software (or an operator, such as CloudNativePG for Postgres) sets up replication. For many teams a managed database is the better choice; for those running their own, use an operator.
Sharp edges
- Retained claims cost money. By default PVCs survive scale-down and deletion (
Retain), which protects data but leaves disks behind.persistentVolumeClaimRetentionPolicy(stable since 1.32) can setDeleteper case. - Volumes live in one zone. A pod bound to a zonal disk can only be rescheduled in that zone; use
volumeBindingMode: WaitForFirstConsumerin the StorageClass so the disk is created where the pod is scheduled. - Stuck rollouts. With the default
OrderedReadypolicy, a broken pod blocks the update; after fixing the template you may have to delete that pod by hand. - Graceful shutdown matters more. Give databases a
terminationGracePeriodSecondslong enough to checkpoint, and PodDisruptionBudgets so node drains never take a quorum away.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.