Gendi Notes

Kubernetes Storage

A PVC is a **request** for storage; a PV is the storage itself. You write the request, the cluster finds or creates the disk, and separating those two roles is what makes storage portable between clouds.

Level 3 guide kubernetesstoragevolumes

What is it?#

Container filesystems are destroyed with the container. Anything that must survive needs a volume that outlives the pod.

YOU WRITE CLUSTER DOES CLOUD HAS ───────── ──────────── ───────── PersistentVolumeClaim "10Gi, ReadWriteOnce" → StorageClass picks a → EBS volume (a REQUEST) provisioner and creates vol-0abc123 a PersistentVolume │ binds PVC ←→ PV (1:1, permanent) │ kubelet + CSI attach and mount it into the pod
ObjectWhat it isWho writes it
PersistentVolume (PV)The actual piece of storageUsually the provisioner
PersistentVolumeClaim (PVC)A request for storageYou
StorageClassHow to provision, and with what parametersPlatform team
CSI driverThe plugin that talks to the storage backendInstalled once

How to use it#

A PVC, and a pod that uses it#

pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes: [ReadWriteOnce]
  storageClassName: gp3            # omit → the cluster's default class
  resources:
    requests:
      storage: 20Gi
---
apiVersion: apps/v1
kind: Deployment
spec:
  template:
    spec:
      containers:
        - name: app
          volumeMounts:
            - name: data
              mountPath: /var/lib/app
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: data

Access modes — the constraint people misread#

ModeMeansReality
ReadWriteOnce (RWO)Mountable read-write by one nodeBlock storage: EBS, GCE PD, Azure Disk. Most common
ReadOnlyMany (ROX)Read-only by many nodesRare
ReadWriteMany (RWX)Read-write by many nodesNeeds a filesystem: NFS, EFS, CephFS
ReadWriteOncePodExactly one podNewer; the genuinely exclusive option

StorageClass — where the real decisions live#

storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
provisioner: ebs.csi.aws.com
parameters:
  type: gp3
  encrypted: "true"
reclaimPolicy: Delete              # or Retain — see the warning
allowVolumeExpansion: true         # you WILL need this
volumeBindingMode: WaitForFirstConsumer   # almost always correct
FieldWhy it matters
reclaimPolicy: DeletePVC deleted → the disk and its data are deleted
reclaimPolicy: RetainDisk survives; you clean up manually
allowVolumeExpansion: trueWithout it a full disk cannot be grown, ever
volumeBindingModeImmediate provisions before scheduling — wrong in multi-AZ

Growing a volume#

# Requires allowVolumeExpansion: true on the StorageClass
kubectl patch pvc data -p '{"spec":{"resources":{"requests":{"storage":"50Gi"}}}}'
kubectl get pvc data -w

Expansion is online for most CSI drivers. Shrinking is never supported — plan sizes with that in mind.

What goes wrong#

SymptomCauseFix
PVC stuck PendingNo matching PV, or no default StorageClasskubectl describe pvc → Events
Pod stuck ContainerCreatingVolume cannot attach — usually wrong zone or still attached elsewherekubectl describe pod; check the node's zone
Rollout hangs with an RWO volumeNew pod on a different nodestrategy: Recreate, or a StatefulSet
volume node affinity conflictVolume in AZ-a, pod scheduled to AZ-bWaitForFirstConsumer
Data gone after pod restartemptyDir, not a PVCUse a PVC
Cannot resizeallowVolumeExpansion falseEdit the class; existing PVCs then resize
PVC stuck TerminatingA pod still uses it — the finalizer is protecting youDelete the pod first
Disk full but the PV is largeThe filesystem was not grownMost CSI drivers do it; otherwise restart the pod

Interview corner · الأسئلة اللي بتتسأل#

Explain the relationship between PV, PVC and StorageClass.

It is a separation of concerns between the person who needs storage and the person who provides it.

ObjectAnswersOwned by
PVC"I need 20Gi, ReadWriteOnce"The application developer
StorageClass"Here is how we make that: gp3, encrypted, expandable"The platform team
PVThe actual provisioned diskCreated automatically

Dynamic provisioning is the normal path: you create a PVC naming a StorageClass, the class's provisioner creates a real disk, a PV object is created to represent it, and PVC and PV are bound 1:1 permanently.

Why the indirection is worth it: the same PVC manifest works on AWS, Azure and a laptop cluster. Only the StorageClass differs, and that is not in the application's repository. It is the same plug-in pattern as CRI and CNI.

Static provisioning still exists — an admin pre-creates PVs and PVCs bind to whichever matches — and is used for existing NFS exports or specific hardware.

Why does a Deployment with a PVC often fail to roll out?

Because RollingUpdate starts the new pod before terminating the old one, and a ReadWriteOnce volume can only be attached to one node at a time.

old pod on node-1, volume attached to node-1 │ │ rolling update starts ↓ new pod scheduled to node-2 │ ↓ volume cannot attach to node-2 — still held by node-1 │ ↓ new pod: ContainerCreating forever old pod: never terminated, because the new one is not Ready │ ↓ deadlock

Three fixes, in increasing order of correctness:

  1. strategy: Recreate — the old pod is terminated first. Accepts downtime.
  2. Use a StatefulSet. It replaces pods one at a time, each keeping its own PVC, which is exactly this problem solved properly.
  3. Reconsider whether the workload should hold a volume at all — for many apps the answer is object storage or a managed database.

Key takeaways#

  • PVC is the request, PV is the disk, StorageClass is the recipe. The indirection is what makes manifests portable.
  • ReadWriteOnce is per node, not per pod — two pods on one node both mount it.
  • WaitForFirstConsumer for zonal storage, or pods get stuck Pending in the wrong AZ.
  • reclaimPolicy: Delete destroys data when the PVC goes. Use Retain for production state.
  • allowVolumeExpansion: true from the start. Growing is possible; shrinking never is.
  • Deployments and RWO volumes deadlock. Use Recreate, or a StatefulSet.
  • A retained volume is not a backup until you have tested a restore.

Last updated 2026-09-13