Pods are ephemeral — when one is rescheduled, anything written to its container filesystem is gone. To keep data, Kubernetes separates the storage that exists from the request for storage: the PersistentVolume (PV) and the PersistentVolumeClaim (PVC). This guide explains both, how they bind, static vs dynamic provisioning, and the access modes and reclaim policies you'll be asked about.
Analogy: the PV is a house on the market, the PVC is a request for a house, Kubernetes is the agent that matches them, and the Pod is the person who moves in.
| You need | Why |
|---|---|
| A cluster with a default StorageClass (minikube/kind/EKS/AKS/GKE all have one) | For the dynamic-provisioning demo |
kubectl |
To apply and inspect objects |
| Feature | PV (PersistentVolume) | PVC (PersistentVolumeClaim) |
|---|---|---|
| Full form | PersistentVolume | PersistentVolumeClaim |
| Purpose | Provides storage | Requests storage |
| Created by | Admin / dynamic provisioner | User / application |
| Scope | Cluster-level | Namespace-level |
| Contains | Actual storage details (capacity, path, reclaim policy) | Requirements (size, access mode, class) |
| Used directly by pods? | No | Yes (pods mount the PVC) |
| Relationship | Supplies storage | Claims storage |
On a cloud cluster you usually don't create PVs by hand. You create a PVC, and a StorageClass provisions the PV automatically.
# pvc.yaml — a request; the StorageClass creates the PV on demand
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: demo-pvc
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard # omit to use the cluster default
resources:
requests:
storage: 5Gi
kubectl apply -f pvc.yaml
kubectl get pvc demo-pvc # STATUS should move to Bound
kubectl get pv # a PV was auto-created and bound to the claim
The claim starts Pending, the provisioner creates the disk + PV, and the two become Bound.
The pod references the PVC in volumes and mounts it — it never names the PV:
apiVersion: v1
kind: Pod
metadata:
name: storage-pod
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: app-storage
mountPath: /usr/share/nginx/html
volumes:
- name: app-storage
persistentVolumeClaim:
claimName: demo-pvc
Data written under /usr/share/nginx/html now lives on the PV and survives pod restarts and rescheduling.
For pre-existing storage (an NFS export, a specific disk), an admin creates the PV first; PVCs then bind to whatever matches.
# pv.yaml — admin-created storage
apiVersion: v1
kind: PersistentVolume
metadata:
name: demo-pv
spec:
capacity:
storage: 10Gi
accessModes: ["ReadWriteOnce"]
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath: # demo only; use NFS/EBS/etc. in production
path: /mnt/data
A PVC with a matching storageClassName, size ≤ capacity, and compatible access mode will bind to it.
Static vs dynamic: static = you pre-create a fixed pool of PVs (good for existing hardware/NFS); dynamic = a StorageClass creates storage on demand (the cloud default, far less toil).
Access modes — what can mount the volume, and how:
| Mode | Meaning | Typical backend |
|---|---|---|
ReadWriteOnce (RWO) |
Read-write by one node | Block storage — EBS, Azure Disk, Persistent Disk |
ReadOnlyMany (ROX) |
Read-only by many nodes | Shared/exported storage |
ReadWriteMany (RWX) |
Read-write by many nodes | Shared filesystems — NFS, EFS, Azure Files |
ReadWriteOncePod |
Read-write by one pod | Strict single-writer needs |
The backend decides what's possible: block storage is usually RWO; you need a shared filesystem (NFS/EFS/Azure Files) for RWX.
Reclaim policy — what happens to the storage when the PVC is deleted (persistentVolumeReclaimPolicy):
Delete policy on a database PVC will wipe the disk when the claim is removed. Use Retain for stateful/critical data.Pending. No matching PV (static) or no/instant StorageClass (dynamic), or an access-mode/size mismatch — check kubectl describe pvc.emptyDir dies with the pod; only PVCs survive rescheduling.Pending → Bound, and confirm a PV was auto-created (kubectl get pv).ReadWriteMany on a block-storage class and read the kubectl describe pvc event to see why it won't bind.kubectl get storageclass -o yaml) — is it Delete or Retain?Self-check:
Delete reclaim policy do when you remove the PVC?volumeClaimTemplates.The takeaway: PV supplies storage, PVC requests it, Kubernetes binds them, and pods mount the claim — separating the two is what lets storage outlive ephemeral pods.
Learned the concepts? Test yourself with Kubernetes interview questions.
Go to the question bank →