Kubernetes persistent volumes and PVCs: how a pod gets a disk

On AKS and EKS, a claim usually becomes an Azure disk or EBS volume, charged by its size.

Published 2 November 2026 · Published by Zoorik

Kubernetes persistent volume: a pod mounts a PVC, the PVC binds to a PV, and the PV points to an Azure disk or an EBS volume

Short answer. A persistent volume (PV) is a piece of cluster storage whose lifecycle is independent of any pod that uses it. A PersistentVolumeClaim (PVC) is a request for that storage: it asks for a size and an access mode, and binds to one matching PV. Pods mount the claim, so the data stays when a pod is deleted or replaced.

Why pods need persistent volumes

When a container crashes or stops, the files it created or changed are lost. After a crash, the kubelet restarts it with a clean state.

Ephemeral volumes have a lifetime linked to one pod. Kubernetes destroys them when the pod ceases to exist, but it doesn’t destroy persistent volumes.

A PV is a resource in the cluster, just as a node is. The PV object records the details of the storage behind it, be that NFS, iSCSI or a cloud provider’s storage system.

What a Kubernetes PVC is and how it binds

A PVC is a user’s request for storage. Just as a pod requests CPU and memory from a node, a claim requests a size and access modes from a PV. It usually names a StorageClass too, and it lives in the same namespace as the pods that use it.

A control loop in the control plane watches for new claims and binds each one to a matching PV. The binding is one to one, and no other claim can use that PV. A claim always gets at least the size it asked for, and the PV may be larger.

A claim with no match stays unbound until one appears. In the docs’ example, a cluster with many 50 GiB PVs can’t bind a claim for 100 GiB. It binds once a 100 GiB PV is added.

A PV is always in one of four phases:

  • Available: free, and not yet bound to a claim.
  • Bound: bound to a claim.
  • Released: the claim was deleted, but the cluster hasn’t reclaimed the storage yet.
  • Failed: its automatic reclamation failed.

Deleting a claim that a pod still uses doesn’t remove it at once, because that could lose data. The claim shows Terminating, with the kubernetes.io/pvc-protection finalizer, until no pod uses it.

Static and dynamic provisioning

A PV is provisioned in one of two ways. Statically, a cluster administrator creates PVs ahead of time, each one pointing at real storage. Dynamically, when no static PV matches a claim, the cluster can create one for it from the claim’s StorageClass.

A static PV waits for a claim, and a dynamic PV is made for one Two lanes. Static: an administrator creates PVs before any claim. An arrow labelled creates first leads from Administrator to the subject, a PV that is Available, waiting. A PVC, a claim that matches, points back at it with an arrow labelled binds to it. Dynamic: when no PV matches a claim. A PVC that names a class points, names, to a StorageClass with its provisioner, which creates the subject, a PV and cloud disk made for the claim. A line from it back to the PVC reads bound to the claim that asked for it. A static PV waits for a claim, and a dynamic PV is made for one Statican administrator creates PVs before any claimAdministratorPVAvailable, waitingPVCa claim that matchescreates firstbinds to itDynamicwhen no PV matches a claimPVCnames a classStorageClassits provisionerPV and cloud diskmade for the claimnamescreatesbound to the claim that asked for it
With dynamic provisioning, the claim comes first, and its class makes the PV and the disk for it.

A claim that names no class gets the cluster’s default StorageClass: the one annotated storageclass.kubernetes.io/is-default-class: "true". A claim with storageClassName: "" binds only to PVs without a class, and dynamic provisioning is off for it.

On AKS, the default class is named default, and it’s the same as managed-csi, one of the built-in AKS storage classes. It creates a Standard SSD managed disk. From Kubernetes 1.29, on clusters deployed across multiple availability zones, that disk is zone-redundant (ZRS) instead of locally redundant (LRS).

On EKS, the Amazon EBS CSI driver, ebs.csi.aws.com, creates EBS volumes for persistent volumes. EKS Auto Mode needs no EBS CSI controller installed. Its storage classes must name its own provisioner, ebs.csi.eks.amazonaws.com.

A class’s volumeBindingMode sets when it makes the volume. Immediate, the default, binds and provisions it as soon as the claim is created, without knowing where its pod will run. For storage that some nodes can’t reach, such as a disk in one zone, that can leave the pod unschedulable.

WaitForFirstConsumer waits for a pod that uses the claim. The volume is then placed to suit the pod’s scheduling constraints, such as the zone it can run in.

Access modes

A claim asks for one or more access modes, and Kubernetes matches it to a PV that offers them:

  • ReadWriteOnce (RWO): read-write by a single node. Several pods on that node can still use it.
  • ReadOnlyMany (ROX): read-only by many nodes.
  • ReadWriteMany (RWX): read-write by many nodes.
  • ReadWriteOncePod (RWOP): read-write by a single pod in the whole cluster. It works only with CSI volumes, and it’s stable since Kubernetes 1.29.

An Azure disk is mounted as ReadWriteOnce, so only one node can use it. For pods on several nodes at once, Microsoft points to Azure Files. A volume is mounted with only one access mode at a time, even if it supports several.

Reclaim policies

A PV’s reclaim policy decides what happens to it after its claim is deleted:

  • Retain: the PV stays, Released, with the old data on it. You delete the PV, then clean up or delete the cloud disk yourself.
  • Delete: removes both the PV and the storage behind it, such as the Azure disk or EBS volume.
  • Recycle: deprecated. The docs recommend dynamic provisioning instead.

A dynamically provisioned PV inherits its class’s reclaim policy, and a class that sets none defaults to Delete. AKS’s built-in disk classes delete the Azure disk when its persistent volume is deleted.

A Kubernetes persistent volume example

The claim below asks for 10 GiB, read-write on one node, from AKS’s managed-csi class. On EKS, name a StorageClass that uses the EBS CSI driver instead. The pod after it mounts the claim at /data.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: data
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: managed-csi
  resources:
    requests:
      storage: 10Gi
apiVersion: v1
kind: Pod
metadata:
  name: web
spec:
  containers:
    - name: web
      image: nginx
      volumeMounts:
        - mountPath: /data
          name: data
  volumes:
    - name: data
      persistentVolumeClaim:
        claimName: data

kubectl describe pvc data shows the claim’s status and, once it’s bound, the PV behind it. On a class with WaitForFirstConsumer, the claim stays unbound until the pod is created.

Delete the pod and create it again, and the files in /data are still there. The claim and its PV outlive the pod.

A StatefulSet needs no hand-written claim. Each entry in its volumeClaimTemplates gives every pod its own claim, and with it stable storage.

Kubernetes persistent storage on AKS and EKS: what you pay for

EBS charges for the GB you provision each month, until you release the storage. Azure prices a managed disk at the closest size tier that fits it, and charges the same however much of it is used.

So a claim is charged by its size, not by its data. A 128 GiB claim holding 20 GiB is charged for all 128 GiB.

A 128 GiB claim holding 20 GiB of data is charged for 128 GiB A PVC that requests 128Gi leads, by dynamic provisioning, to the subject, an EBS volume or Azure Standard SSD of 128 GiB. Inside it, one bar drawn to scale: 20 GiB of data and 108 GiB empty, still charged. A bracket over the whole bar reads charged: all 128 GiB. A 128 GiB claim holding 20 GiB of data is charged for 128 GiB PVCrequests 128Gidynamic provisioningEBS volume or Azure Standard SSD128 GiBcharged: all 128 GiBdata20 GiBempty, still charged108 GiB
Illustration: the sizes are examples. EBS charges per GB provisioned, and Azure charges a 128 GiB Standard SSD as an E10.

You can resize a PVC to a larger size when its class sets allowVolumeExpansion: true. It can’t shrink, so space you size for later is charged now.

Deleting or scaling down a StatefulSet keeps its claims and their disks by default. Its persistentVolumeClaimRetentionPolicy, stable since Kubernetes 1.32, can delete the claims instead.

Sources: Kubernetes, “Persistent Volumes” (opens in a new tab); Kubernetes, “Storage Classes” (opens in a new tab); Kubernetes, “Volumes” (opens in a new tab); Kubernetes, “StatefulSets” (opens in a new tab); Microsoft Learn, “Concepts - Storage in Azure Kubernetes Service (AKS)” (opens in a new tab); AWS, “Use Kubernetes volume storage with Amazon EBS” (opens in a new tab); AWS, “Amazon EBS pricing” (opens in a new tab); Microsoft Azure, “Managed Disks pricing” (opens in a new tab).

Find your own number

One line in your cloud console. One PDF report with your estimated saving at list price.

Estimate your saving
Talk to the builders

Thirty minutes with the people who build Coral.

Book a demo (opens in a new tab)

Or write to founders@zoorik.com