Skip to content
Lucas Mauro

How does Persistent Storage in Kubernetes work?

How can we avoid losing our data?

kubernetes 2 min read

Most Volumes are ephemeral: they disappear when so does the pod. For anything that needs to persist (databases, file uploads, application state), we need storage that lives beyond the pod’s lifetime, and that is precisely where this concept of persistent storage comes in.

In summary, persistent storage in Kubernetes is built around three objects that work together: a PersistentVolume (PV), a PersistentVolumeClaim (PVC), and a StorageClass. We can think of it as the following: we ask for storage via a claim, Kubernetes provisions the actual volume, and we mount it in our pod.

A PVC is our request for storage. It says “I need X gigabytes, mounted in this way.” It is similar to how a Pod requests CPU and memory: we declare what we need, and Kubernetes finds or creates a match.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: standard

The key fields:

  • accessModes tells Kubernetes how the volume will be mounted: ReadWriteOnce (single node, read/write), ReadOnlyMany (multiple nodes, read-only), or ReadWriteMany (multiple nodes, read/write);
  • resources.requests.storage is how much space we need;
  • storageClassName tells Kubernetes which provisioner to use (more on this below).

A PV is the actual storage resource. It represents a real disk or network volume somewhere in the infrastructure. In the past, admins had to create PVs manually before anyone could use them. With dynamic provisioning (via StorageClasses), Kubernetes handles this for us, which is why we rarely create PVs directly.

apiVersion: v1
kind: PersistentVolume
metadata:
name: my-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: standard
hostPath:
path: /mnt/data

A few things worth noting:

  • persistentVolumeReclaimPolicy determines what happens when the PVC is deleted: Retain keeps the data (an admin must clean it up), Delete removes the storage entirely;
  • hostPath is just one possible backend. In practice, PVs are usually backed by cloud storage (EBS, Persistent Disks, Azure Disks) or network storage (NFS, Ceph).

A StorageClass defines how storage gets provisioned. It is the blueprint that Kubernetes follows when a PVC asks for storage dynamically. Most managed Kubernetes platforms come with a default StorageClass already configured, so we often do not need to create one ourselves.

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp3
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumer
  • provisioner tells Kubernetes which storage backend to use (AWS EBS here);
  • volumeBindingMode controls when the volume gets created: WaitForFirstConsumer waits until a pod using the PVC is scheduled, which matters in multi-zone clusters (we want the storage in the same zone as the pod).

  1. We create a PVC asking for storage (size, access mode, storage class);
  2. Kubernetes uses the StorageClass to provision a PV that matches our request;
  3. The PVC is bound to the PV;
  4. We mount the PVC in a pod, just like any other Volume.
# Inside a pod spec
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: my-pvc
containers:
- name: my-app
volumeMounts:
- name: persistent-storage
mountPath: /app/data

These come up in both PVCs and PVs:

  • ReadWriteOnce (RWO): read/write by a single node;
  • ReadOnlyMany (ROX): read-only by many nodes;
  • ReadWriteMany (RWX): read/write by many nodes.

It is worth noting that not every storage backend supports every mode, though. A local disk only supports RWO, while network storage like NFS can support RWX. We should pick the right one based on how our application actually uses storage.

Comments