What Is a Kubernetes PersistentVolume and PersistentVolumeClaim? Explained Simply
Kubernetes PersistentVolume (PV) and PersistentVolumeClaim (PVC) explained for beginners — what they are, how pods use them for storage, the binding lifecycle, StorageClass dynamic provisioning, and common patterns.
Kubernetes pods are ephemeral — when a pod restarts, everything written to its filesystem is gone. For applications that need data to survive pod restarts (databases, file uploads, logs), Kubernetes provides persistent storage through PersistentVolumes.
The way this works involves two objects that often confuse beginners: PersistentVolume (PV) and PersistentVolumeClaim (PVC). Here is what they are and how they work together.
The Apartment Analogy
Think of it this way:
- PersistentVolume (PV) = an apartment that exists and is available to rent. It has specific characteristics: size, location, features.
- PersistentVolumeClaim (PVC) = a rental application where you specify what you need: "I need a 2-bedroom apartment in downtown."
- Binding = the process of matching a suitable apartment to a rental application.
The tenant (your pod) does not directly care about which specific apartment they get — they just need an apartment that meets their requirements. The pod only interacts with the PVC (the claim), not the PV directly.
PersistentVolume (PV)
A PV represents a piece of storage in the cluster — an actual disk or storage system. It can be:
- An AWS EBS volume
- A Google Persistent Disk
- An NFS share
- A local disk on a node
- Azure Disk or Azure Files
apiVersion: v1
kind: PersistentVolume
metadata:
name: manual-pv-100gi
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteOnce # Can only be mounted by one node at a time
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
awsElasticBlockStore:
volumeID: vol-0a1b2c3d4e5f6g7h8
fsType: ext4In practice, you rarely create PVs manually anymore — StorageClasses handle this automatically (dynamic provisioning). But understanding the PV object helps you understand what exists.
PersistentVolumeClaim (PVC)
A PVC is a request for storage. Your pod does not talk to the storage directly — it references a PVC, and Kubernetes handles binding the PVC to an appropriate PV.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-database-storage
namespace: production
spec:
accessModes:
- ReadWriteOnce # Must match PV's access mode
storageClassName: gp3 # Which StorageClass to use
resources:
requests:
storage: 20Gi # How much storage you needAccess Modes
Access modes define how the volume can be mounted:
| Mode | Short | Meaning |
|---|---|---|
| ReadWriteOnce | RWO | One node can read/write. Most common for databases. |
| ReadOnlyMany | ROX | Many nodes can read (no writes). Good for shared config. |
| ReadWriteMany | RWX | Many nodes can read/write. Requires shared storage like NFS or EFS. |
EBS volumes (and most block storage) only support ReadWriteOnce. If you need ReadWriteMany, you need shared storage — AWS EFS, NFS, or Ceph.
Using a PVC in a Pod
Once you have a PVC, mount it in your pod like this:
apiVersion: v1
kind: Pod
metadata:
name: postgres
spec:
containers:
- name: postgres
image: postgres:16
env:
- name: POSTGRES_PASSWORD
value: "changeme"
volumeMounts:
- name: postgres-data # References the volume name below
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: my-database-storage # References the PVCThe pod mounts the PVC at /var/lib/postgresql/data. Data written there survives pod restarts — PostgreSQL's data files persist on the actual disk.
StorageClass and Dynamic Provisioning
Manually creating PVs is tedious. StorageClasses automate this — when a PVC is created with a StorageClass, Kubernetes automatically provisions a PV that meets the claim's requirements.
# StorageClass definition (usually pre-installed in managed clusters)
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: gp3
provisioner: ebs.csi.aws.com # The CSI driver that creates EBS volumes
parameters:
type: gp3
encrypted: "true"
reclaimPolicy: Delete
volumeBindingMode: WaitForFirstConsumerWhen you create a PVC that references storageClassName: gp3, the EBS CSI driver automatically:
- Creates an EBS gp3 volume with the requested size
- Creates a PV representing that volume
- Binds the PV to your PVC
You never write any YAML for the PV — it appears automatically.
# Watch the binding happen
kubectl get pvc my-database-storage -n production -w
# NAME STATUS VOLUME CAPACITY
# my-database-storage Pending - - (waiting for pod)
# my-database-storage Bound pvc-abc123def456 20Gi (after pod is scheduled)The PVC Lifecycle
PVC Created (Pending)
↓
StorageClass provisions a PV automatically
↓
PVC Bound to PV
↓
Pod mounts PVC
↓
Pod deleted → PVC and PV remain (data safe)
↓
PVC deleted → depends on reclaimPolicy:
- Delete: PV deleted, EBS volume deleted (data gone)
- Retain: PV stays (data preserved), must be manually reclaimed
reclaimPolicy: Retain is safer for production — if you accidentally delete a PVC, the underlying EBS volume is not deleted automatically. You have to clean it up manually but at least you have a chance to recover data.
Common Patterns
Database with StatefulSet (recommended):
# StatefulSet automatically creates PVCs per pod
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp3
resources:
requests:
storage: 100GiEach StatefulSet pod gets its own PVC (data-postgres-0, data-postgres-1) that sticks to that pod permanently.
Shared configuration (ReadOnlyMany with NFS/EFS):
# For configuration files shared across pods
spec:
accessModes:
- ReadOnlyMany
storageClassName: efs-sc # AWS EFS StorageClass
resources:
requests:
storage: 1Gi # EFS ignores this — it is elasticKey Commands
# List PVCs in a namespace
kubectl get pvc -n production
# Check PVC status and which PV it is bound to
kubectl describe pvc my-database-storage -n production
# List PVs in the cluster
kubectl get pv
# See which PVC a PV is bound to
kubectl get pv pvc-abc123def456Ready for more storage topics? Read our Kubernetes PVC stuck in Pending fix and Kubernetes StatefulSet vs Deployment guide.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Build a Kubernetes Cluster with kubeadm from Scratch (2026)
Step-by-step guide to building a real multi-node Kubernetes cluster using kubeadm — no managed services, no shortcuts.
How to Build a DevOps Home Lab for Free in 2026
You don't need expensive hardware to practice DevOps. Here's how to build a complete home lab with Kubernetes, CI/CD, and monitoring using free tools and cloud free tiers.
How to Crack the CKA Exam in 2026: Study Plan, Resources, and Tips
Complete CKA exam prep guide for 2026 — what to study, how to practice, which resources actually help, and tips to pass on the first attempt.