Kubernetes Volumes, PV and PVC Explained
Learn how Kubernetes keeps application data beyond Pod restarts using Volumes, PersistentVolumes, PersistentVolumeClaims and StorageClasses.
Why Kubernetes storage is different
Containers and Pods are replaceable. A container filesystem normally disappears when the container is recreated. A Pod may also move to another node during rescheduling. Persistent storage separates application data from the lifecycle of a specific container or Pod.
Ephemeral data
Temporary files, caches and scratch space that may disappear with the Pod.
Persistent data
Database files, uploaded documents and application state that must survive Pod replacement.
External storage
Cloud disks, network filesystems, CSI-backed storage and other systems mounted into workloads.
The storage relationship
Volume, PV, PVC and StorageClass
- Object — Purpose — Managed by
- Volume — Makes storage available inside a Pod. — Workload author
- PersistentVolume — Represents cluster storage with capacity and access rules. — Administrator or dynamic provisioner
- PersistentVolumeClaim — Requests storage with a size, access mode and optional StorageClass. — Application team
- StorageClass — Defines how storage is dynamically provisioned. — Cluster or platform team
Common volume types
- emptyDir : temporary storage shared by containers in one Pod.
- configMap and secret : mount configuration data as files.
- persistentVolumeClaim : attach persistent storage requested through a PVC.
- hostPath : mounts a node path and should generally be avoided for portable production workloads.
- CSI volumes: storage supplied through a Container Storage Interface driver.
Example: emptyDir for temporary shared files
apiVersion: v1 kind: Pod metadata: name: shared-cache spec: containers: - name: writer image: busybox command: ["sh", "-c", "echo hello > /cache/message; sleep 3600"] volumeMounts: - name: cache mountPath: /cache - name: reader image: busybox command: ["sh", "-c", "cat /cache/message; sleep 3600"] volumeMounts: - name: cache mountPath: /cache volumes: - name: cache emptyDir: {}
The data survives individual container restarts inside that Pod, but it disappears when the Pod is removed.
Static PersistentVolume example
apiVersion: v1 kind: PersistentVolume metadata: name: app-pv spec: capacity: storage: 10Gi accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: manual hostPath: path: /data/app
PersistentVolumeClaim example
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: app-data namespace: dev spec: accessModes: - ReadWriteOnce storageClassName: manual resources: requests: storage: 5Gi
Kubernetes attempts to bind this claim to a compatible PV. Capacity, access mode, StorageClass and other constraints must match.
Use the PVC in a Deployment
apiVersion: apps/v1 kind: Deployment metadata: name: web namespace: dev spec: replicas: 1 selector: matchLabels: app: web template: metadata: labels: app: web spec: containers: - name: nginx image: nginx:1.27 volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data persistentVolumeClaim: claimName: app-data
Access modes explained
- Mode — Meaning — Typical use
- ReadWriteOnce (RWO) — Read-write by a single node. — Cloud block disks and many databases.
- ReadOnlyMany (ROX) — Read-only by multiple nodes. — Shared read-only content.
- ReadWriteMany (RWX) — Read-write by multiple nodes. — Shared network filesystems.
- ReadWriteOncePod (RWOP) — Read-write by a single Pod where supported. — Strict single-writer workloads.
Dynamic provisioning with StorageClass
Dynamic provisioning removes the need to create each PV manually. When a PVC references a StorageClass, the CSI provisioner creates suitable storage automatically.
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-storage provisioner: example.csi.driver reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: WaitForFirstConsumer
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: database-data spec: storageClassName: fast-storage accessModes: - ReadWriteOnce resources: requests: storage: 20Gi
Immediate versus WaitForFirstConsumer
Immediate provisions storage as soon as the claim is created. WaitForFirstConsumer delays binding until a Pod uses the claim, allowing Kubernetes to consider node topology and availability zones before selecting storage.
PV and PVC lifecycle
- A PVC is created and enters Pending .
- Kubernetes finds or provisions a compatible PV.
- The PV and PVC become Bound .
- A Pod mounts the claim.
- When the claim is deleted, the reclaim policy determines what happens to the underlying storage.
Reclaim policies
- Policy — Behavior after PVC deletion — Use carefully because
- Retain — The PV and underlying data are kept for manual recovery or cleanup. — An administrator must deliberately reclaim or delete the data.
- Delete — The provisioned storage is normally deleted with the PV. — Deleting a PVC may permanently delete the underlying data.
Expand a PersistentVolumeClaim
Expansion works only when the StorageClass and CSI driver support it.
kubectl patch pvc database-data \ -p '{"spec":{"resources":{"requests":{"storage":"30Gi"}}}}' kubectl get pvc database-data kubectl describe pvc database-data
StatefulSets and storage
StatefulSets are often used for databases and clustered stateful applications because they provide stable Pod identities and can create one PVC per replica through volumeClaimTemplates .
volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: fast-storage resources: requests: storage: 20Gi
Useful storage commands
kubectl get pv kubectl get pvc -A kubectl describe pvc app-data -n dev kubectl describe pv app-pv kubectl get storageclass kubectl get events -n dev --sort-by=.lastTimestamp kubectl get pod web-POD -n dev -o yaml
Why is my PVC Pending?
- Cause — What to inspect — Typical correction
- No matching PV — Requested size, access mode and StorageClass — Create a compatible PV or use dynamic provisioning.
- StorageClass missing — kubectl get storageclass — Use an available class or configure a default class.
- CSI provisioner failure — Events and CSI controller logs — Fix driver credentials, permissions, topology or quotas.
- Topology conflict — Node zone and volume zone — Use WaitForFirstConsumer where suitable.
- Insufficient capacity — PV capacities and backend limits — Request a supported size or add storage capacity.
Troubleshoot mount failures
kubectl describe pod APP_POD -n dev kubectl get events -n dev --sort-by=.lastTimestamp kubectl describe pvc app-data -n dev kubectl describe pv PV_NAME kubectl get volumeattachments
Common messages include FailedMount , FailedAttachVolume , multi-attach errors, missing CSI drivers and permission problems inside the mounted filesystem.
Backups and snapshots
A PV is not a backup. Protect important data using application-aware backups, database dumps, replication and CSI VolumeSnapshots where supported. Test restores regularly; a backup that has never been restored is only an assumption.
Common mistakes
- Running a database only on the container filesystem.
- Assuming all StorageClasses support RWX or volume expansion.
- Deleting a PVC without checking the reclaim policy.
- Using hostPath for production data that must survive node failure.
- Creating multiple replicas that all expect exclusive write access to one RWO volume.
- Treating snapshots as the only backup strategy.
- Ignoring storage capacity and inode monitoring.
Production best practices
- Use a supported CSI driver and documented StorageClasses.
- Choose access modes based on the storage backend and application design.
- Prefer WaitForFirstConsumer for topology-aware block storage.
- Use dedicated PVCs for important stateful workloads.
- Encrypt storage and protect backup credentials.
- Monitor capacity, latency, IOPS, filesystem usage and failed mount events.
- Document reclaim policies and deletion procedures.
- Test failover, backup and restore before production incidents.
Hands-on practice lab
kubectl create namespace storage-lab kubectl apply -f pv.yaml kubectl apply -f pvc.yaml kubectl get pv,pvc -n storage-lab kubectl apply -f pod.yaml kubectl exec -n storage-lab storage-pod -- sh -c 'echo persistent > /data/test.txt' kubectl delete pod storage-pod -n storage-lab kubectl apply -f pod.yaml kubectl exec -n storage-lab storage-pod -- cat /data/test.txt
The final command demonstrates that the file remains when a new Pod mounts the same claim.
Frequently asked questions
No. A PVC is a request and reference. The data is stored in the underlying volume represented by the bound PV.
It depends on the access mode and storage backend. RWX supports multiple-node read-write mounting, while many block volumes provide RWO.
Yes, when the Pod uses persistent storage and the PVC/PV remain available.
That depends on the PV reclaim policy and storage provider. With Delete, the underlying storage may be removed.
No. Stateless services and temporary caches may not need persistent storage. Use PVCs when data must survive workload replacement.
Related Melochip guides
- Kubernetes Learning Path
- Kubernetes Pods Explained
- Kubernetes Deployments and ReplicaSets
- Docker Volumes Explained
- Kubernetes Troubleshooting Guide
Official references
- Kubernetes Persistent Volumes documentation
- Kubernetes StorageClasses documentation
Join the discussion
0 CommentsAsk questions, add context, or share what worked.
More from Melochip Editorial
Learn what Playwright testing is, why modern QA teams use it, how testers can get started, and the major types...
7 min read · Sep 19, 2026
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes security best practices with RBAC, Secrets, ServiceAccounts, Pod securityContext, NetworkPoli...
6 min read · Sep 17, 2026Related articles
Learn how Kubernetes Deployments and ReplicaSets work with practical YAML, scaling, self-healing, rolling upda...
7 min read · Sep 17, 2026
Learn Kubernetes Ingress with controllers, IngressClass, host and path routing, TLS, DNS, annotations, redirec...
8 min read · Sep 17, 2026
Learn Kubernetes monitoring and logs with kubectl logs, events, metrics-server, top commands, Prometheus, Graf...
5 min read · Sep 17, 2026
Learn Kubernetes ConfigMaps and Secrets with YAML, environment variables, file mounts, update behavior, immuta...
8 min read · Sep 17, 2026Stay in the loop. Get new Melochip articles
Receive Melochip article updates when new articles are available. Explicit opt-in only.
No comments yet. Start the discussion.