GCP ACE: Persistent Storage in GKE — PersistentVolumes, Claims, and StorageClasses
Containers are disposable by design — but the StatefulSet article made the point that some workloads (databases especially) need storage that survives a Pod being deleted and recreated. This is the layer that provides it.
The three objects
| Object | What it is |
|---|---|
| PersistentVolume (PV) | A cluster-level resource representing actual durable storage — in GKE, almost always a Compute Engine persistent disk. Its lifecycle is independent of any Pod: deleting a Pod does not delete the PV. |
| PersistentVolumeClaim (PVC) | A request for storage: a size, an access mode, and (optionally) a StorageClass. Kubernetes binds it to a PV that satisfies it, or dynamically provisions a new one. |
| StorageClass | A template that defines how a PV gets provisioned — which provisioner (the Compute Engine persistent disk CSI driver, in GKE’s case), disk type, and filesystem. |
A Pod never talks to a PV directly — it mounts a PVC, and the PVC is bound to a PV behind the scenes.
How it maps to Compute Engine disks
- Dynamic provisioning creates a brand-new, empty Compute Engine persistent disk for each PV, on demand, as soon as a PVC requests one (and a StorageClass exists to satisfy it).
- Zonal disks are the default — the disk lives in one zone, and any Pod using it must be scheduled into that same zone.
- Regional persistent disks replicate the data across two zones in a region, so the volume survives a zone outage — at the cost of extra replication overhead.
- Mounting a disk from a different Google Cloud project isn’t supported.
Default behavior if you don’t specify a StorageClass
GKE ships a default StorageClass using the balanced persistent disk type with ext4. Any PVC that omits storageClassName gets this default automatically.
Two defaults worth memorizing:
- Reclaim policy:
Deleteby default — deleting the PVC deletes the underlying PV and the disk. Switch toRetainif you need the disk to survive PVC deletion (it then becomes aReleasedPV you have to clean up or rebind manually). - Binding mode on
standard-rwo:WaitForFirstConsumer— the actual disk isn’t created until a Pod using the PVC is scheduled, so the disk lands in the same zone as that Pod rather than a zone picked at random.
Windows node pools are the one exception to all of this: ext4 isn’t supported there, so Windows workloads need an explicit StorageClass using NTFS.
Example
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-demo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 30Gi
storageClassName: standard-rwo
This requests 30 GiB that a single node can mount read-write. Setting storageClassName explicitly pins the claim to standard-rwo (the balanced persistent disk class backed by the Compute Engine PD CSI driver), regardless of which StorageClass is currently marked as the cluster default.
# referencing the PVC from a Pod
volumes:
- name: data
persistentVolumeClaim:
claimName: pvc-demo
Exam Takeaways
- PV = the actual storage resource; PVC = a request for storage; StorageClass = the template that defines how a PV gets dynamically provisioned.
- In GKE, PVs are backed by Compute Engine persistent disks (or Filestore for NFS use cases).
- Zonal disks are the default; a Pod using one must be scheduled into that disk’s zone. Regional persistent disks replicate across two zones for failover.
- The default StorageClass uses the
balanceddisk type with ext4;storageClassNameomitted on a PVC means “use the default.” - Default reclaim policy is
Delete— deleting the PVC deletes the PV and the underlying disk. UseRetainto keep the disk. WaitForFirstConsumerbinding mode delays disk creation until a Pod is scheduled, so the disk’s zone matches the Pod’s — this is what prevents a disk from landing in a zone with no capacity for the Pod.- A disk cannot be mounted from a different Google Cloud project.
- Windows node pools need an explicit NTFS-based StorageClass — the default ext4 doesn’t work there.