Persistent storage is where many Kubernetes quickstarts stop feeling simple. Pods are replaceable by design, but data is not. PV and PVC are the abstraction Kubernetes uses to separate storage needs from storage implementation.
What PV and PVC mean
- PV: a piece of storage available to the cluster.
- PVC: a request for storage made by a workload.
- Binding: Kubernetes matching one claim to one suitable volume.
- StorageClass: the policy that describes how new storage should be provisioned.
Think of it like this: the application says what it needs, and the cluster decides how to satisfy that request.
Why this abstraction matters
Without PV and PVC, every workload would need to know storage vendor details. That couples application YAML to infrastructure decisions. Kubernetes separates those concerns so workloads can ask for size, access mode, and class, while storage backends handle implementation details.
That separation is useful for portability, but it also creates a new troubleshooting layer. When storage breaks, the Pod often looks guilty even though the root cause lives in claims, volumes, or provisioners.
The basic flow
- A workload requests storage through a PVC.
- Kubernetes looks for a matching PV, or dynamically provisions one through a StorageClass.
- The PVC becomes
Bound. - A Pod mounts the claim.
- The application reads and writes data through that mounted path.
When dynamic provisioning is enabled, the key link is StorageClass -> provisioner. The PVC references a storageClassName, the StorageClass points to a provisioner or CSI driver, and that backend creates the actual volume on demand.
Dynamic provisioning vs static provisioning
Dynamic provisioning
This is the default in many clusters. A PVC references a StorageClass, and the storage backend creates a volume on demand.
In other words, PVC does not directly create storage by itself. It asks for storage, and the StorageClass tells Kubernetes which provisioner should fulfill that request.
Use this when:
- your cluster already has a working storage provisioner
- you want less manual work
- you want consistent day-to-day developer workflows
Static provisioning
An administrator creates the PV first, and workloads later bind to it.
Use this when:
- storage must be pre-created for policy reasons
- you are migrating existing volumes
- you need tighter manual control over specific disks or exports
Minimal example
This is the smallest pattern most people need to understand first.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: standard
---
apiVersion: v1
kind: Pod
metadata:
name: app
spec:
containers:
- name: app
image: nginx:1.25
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data
Access modes: what they really imply
ReadWriteOnce(RWO): usually one node can mount the volume read-write.ReadWriteMany(RWX): multiple nodes can share the same volume read-write.ReadOnlyMany(ROX): multiple nodes can mount read-only.
The exact behavior depends on the storage backend, so access modes are not just a YAML preference. They reflect real storage capabilities.
Reclaim policy: what happens after delete
This matters more than many beginners expect.
Delete: the underlying volume is removed when the claim is deleted.Retain: the underlying volume stays behind for manual cleanup or reuse.
If you care about preserving data after accidental claim deletion, Retain deserves serious attention. If you want disposable environments, Delete may be better.
Expansion and snapshots
Many backends support PVC expansion, but the workflow is still worth understanding. Growing the claim is only part of the job; sometimes the filesystem also needs to grow.
Snapshots are different from ordinary persistence. A PVC being mounted safely does not mean you have a backup strategy. Backups and restore drills still need their own process.
StorageClass in one paragraph
StorageClass is where you express the default storage policy for a cluster or workload group. It can influence provisioning backend, performance class, reclaim behavior, binding mode, and sometimes topology.
If PV/PVC is the storage contract, StorageClass is the policy engine behind the contract.
That is why kubernetes-quickstart-storageclass.md matters so much: it explains which provisioner is behind the class, what reclaim policy applies, and how dynamic provisioning behaves in your cluster.
Common failure modes
PVC stays Pending
Most common causes:
- StorageClass does not exist
- provisioner is not running
- requested size or access mode is unsupported
- topology constraints do not match any available volume placement
Pod stays Pending because claim is not bound
The Pod is often only a downstream symptom. Check the claim first.
Volume exists but mount fails
Now you may be dealing with node-side attach/mount problems, CSI behavior, permissions, or filesystem issues.
A practical troubleshooting order
Use this sequence instead of staring at the Pod first:
kubectl get pvc -n demo
kubectl describe pvc app-data -n demo
kubectl get pv
kubectl describe pv <pv-name>
kubectl get storageclass
kubectl get events -n demo --sort-by=.metadata.creationTimestamp
Then ask:
- Is the PVC
Bound? - Is the right StorageClass referenced?
- Does the backend support the requested access mode and size?
- Is topology or zone placement blocking binding?
- If the claim is bound, is the mount failing later on the node?
Topology and zone awareness
Some storage is zonal. If the scheduler sends a Pod to a node in the wrong zone, the volume may never attach cleanly. This is why binding mode, scheduler behavior, and storage topology all have to line up.
If a cluster spans zones, storage is no longer just a capacity topic. It becomes a scheduling topic too.
Performance and cost tradeoffs
Not all storage is equal.
- local or SSD-backed volumes are faster but often less flexible
- shared network storage is easier to reuse but may add latency
- premium classes help hot paths but raise cost fast
Choose storage based on workload behavior, not just requested capacity. Many teams overspend because they size for fear instead of actual IOPS and throughput needs.
When not to use PVC as your first choice
Do not reach for persistent storage automatically.
- caches may be disposable
- scratch data may fit
emptyDir - some rebuildable workloads are easier to keep stateless
Persistence is valuable, but it also brings cleanup, backup, migration, and restore responsibilities.
FAQ
Q: If my Pod is Pending, should I start with the Pod description?
A: Look at the Pod, but immediately inspect the PVC as well. Storage-related Pending states are often caused by claim binding, not Pod spec errors.
Q: Is a PV the same thing as a backup? A: No. A PV only provides persistence. Backup and restore still need their own workflow, tooling, and recovery testing.
Q: When should I care about Retain vs Delete reclaim policy?
A: Any time accidental data loss matters. Reclaim policy decides what survives claim deletion, so it directly affects cleanup and recovery behavior.
Next reading
- Continue with
kubernetes-quickstart-storageclass.mdfor provisioning policy. - Read
kubernetes-quickstart-statefulset.mdto see how storage and stable identity come together. - If you run databases, continue into the MySQL quickstart pages.
Wrap-up
When storage gets weird, the Pod is often just the messenger. Check the claim, the class, the provisioner, and the topology before blaming the workload.