Chapter 31 of 47 · Storage, part 2

PersistentVolumes and PersistentVolumeClaims

For data that must outlive any Pod, Kubernetes separates two things: the storage itself (a PersistentVolume, PV) and an app's request for storage (a PersistentVolumeClaim, PVC). The app asks for "10Gi, one writer", and Kubernetes finds a matching disk. This chapter covers static provisioning: an admin creates the disks in advance.

The idea: a parking garage

PersistentVolume = a parking space

A real piece of storage: a cloud disk, an NFS share, a local SSD. Created by the cluster admin. Has a size and rules. Exists on its own, not inside any Pod or namespace.

PersistentVolumeClaim = a parking ticket

Written by the developer: "I need a space for 10Gi". Kubernetes matches the ticket to a free space and they are bound, one to one. Lives in your namespace.

Why split them? Your app YAML stays the same on every cluster. Only the PVs change: NFS on-premise, EBS on AWS, a folder on minikube.

Pod → PVC → PV → disk

The storage chain Podmounts the claim PVC"10Gi, RWO" bound PV10Gi, RWO Real diskNFS, EBS, SSD… you write these twothe admin (or a StorageClass) provides these

The three YAMLs

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-medium
spec:
  capacity:
    storage: 10Gi
  accessModes: [ReadWriteOnce]
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  nfs:                          # where the data really is
    server: 10.0.0.5
    path: /exports/blog

No namespace: PVs belong to the whole cluster. The last block says what kind of storage it is: nfs, csi (cloud disks), local, or hostPath for experiments.

Access modes

ModeShortMeansTypical storage
ReadWriteOnceRWORead-write, mounted by one node at a time (Pods on that node may share it)Cloud block disks (EBS, Persistent Disk)
ReadOnlyManyROXRead-only, many nodesShared reference data
ReadWriteManyRWXRead-write, many nodes at onceNFS, EFS, Azure Files, CephFS
ReadWriteOncePodRWOPRead-write, exactly one PodCSI disks, when you need a guarantee

Most disks are RWO. Needing RWX usually means you need a shared file system, which is slower and more expensive.

Try binding

The admin created four PVs. Create claims of different sizes and modes. Kubernetes binds each claim to the smallest available PV that fits. Then delete a claim and see what happens to its PV.

A PV's lifecycle

Available ──(a PVC matches)──▶ Bound ──(PVC deleted)──▶ Released ──▶ ?
                                                              │
                                     reclaimPolicy: Retain ───┤ data kept, admin cleans up by hand
                                     reclaimPolicy: Delete ───┘ PV and disk deleted (next chapter)

A Released PV still has the old data and cannot be bound again automatically, so one team's data never leaks to the next claim.

With kubectl

$ kubectl get pv
NAME        CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM                STORAGECLASS
pv-medium   10Gi       RWO            Retain           Bound    default/posts-data   manual
pv-small    5Gi        RWO            Retain           Available                     manual

$ kubectl get pvc
NAME         STATUS   VOLUME      CAPACITY   ACCESS MODES   STORAGECLASS
posts-data   Bound    pv-medium   10Gi       RWO            manual

$ kubectl describe pvc big-claim        # when it is Pending
Events:
  Normal  FailedBinding  no persistent volumes available for this claim and no storage class is set

Deployments, replicas and RWO

A Deployment with replicas: 3 and one RWO claim: all three Pods share the same claim. If they land on different nodes, only the first can mount it; the others hang in ContainerCreating with "Multi-Attach error". Two ways out:

Shared data

All replicas really need the same files → use RWX storage (NFS/EFS). Or better: put the data in a database or object storage (S3), not on a disk.

Own data per replica

Each replica needs its own disk (databases) → a StatefulSet with volumeClaimTemplates. It creates data-db-0, data-db-1… and db-1 always gets db-1's disk back (chapter 26).

volumeClaimTemplates:
  - metadata:
      name: data
    spec:
      accessModes: [ReadWriteOnce]
      resources:
        requests:
          storage: 10Gi

Recap

PersistentVolumes and PersistentVolumeClaims: common questions

What is the difference between a PV and a PVC?

A PersistentVolume is a piece of real storage in the cluster. A PersistentVolumeClaim is an app request for storage. Kubernetes binds a claim to a matching volume, one to one.