Persistent Storage in Kubernetes: PVs, PVCs & StorageClasses
In this tutorial, you'll learn about Persistent Storage in Kubernetes: PVs, PVCs & StorageClasses. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
Kubernetes persistent storage decouples storage from pod lifecycle using PersistentVolumes and PersistentVolumeClaims, enabling stateful applications to retain data across restarts, rescheduling, and node failures.
What You'll Learn
This tutorial covers static and dynamic volume provisioning, PersistentVolumeClaims, StorageClasses for cloud volumes, access modes and reclaim policies, StatefulSet storage patterns, and backup strategies for persistent data.
Why It Matters
Without persistent storage, databases, Message Queues, and file stores lose all data when pods restart. Understanding Kubernetes storage is essential for running production stateful workloads -- over 40 percent of production Kubernetes clusters now run stateful applications.
Real-World Use
GitLab uses PersistentVolumeClaims with Cloud Computing StorageClasses to provide persistent storage for Git repositories across all their SaaS customers. MongoDB operators use StatefulSets with persistent storage to handle automatic failover and data Replication across availability zones.
graph TD A[Pod] --> B[PVC: PersistentVolumeClaim] B --> C[PV: PersistentVolume] C --> D[StorageClass] D --> E[Cloud Storage: EBS / GCE PD / Azure Disk] C --> F[Reclaim Policy: Delete / Retain / Recycle] B --> G[Access Mode: RWO / RWX / ROX]
Expected output: diagram showing the storage chain from Pod to PVC to PV to StorageClass to actual cloud storage, with reclaim policies and access modes highlighted.
PersistentVolumes and PersistentVolumeClaims
A PV is cluster storage provisioned by an administrator. A PVC is a request for storage by a user.
# PersistentVolume -- static provisioning
apiVersion: v1
kind: PersistentVolume
metadata:
name: nfs-storage-1
spec:
capacity:
storage: 100Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
nfs:
path: /export/data
server: nfs-server.internal
---
# PersistentVolumeClaim
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: ""
# List PersistentVolumes
kubectl get pv
# List PersistentVolumeClaims
kubectl get pvc
# Check PVC binding status
kubectl describe pvc data-claim
Expected output: PVs show their capacity and status (Available or Bound). The PVC shows Bound status with the matched PV name, indicating the volume is ready for pod consumption.
StorageClasses and Dynamic Provisioning
StorageClasses define different tiers of storage and enable automatic volume creation.
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast-ssd
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: standard
provisioner: kubernetes.io/gce-pd
parameters:
type: pd-standard
reclaimPolicy: Delete
# List available StorageClasses
kubectl get storageclass
# Set default StorageClass
kubectl annotate storageclass fast-ssd storageclass.kubernetes.io/is-default-class="true"
Expected output: storageclasses list shows provisioner, reclaim policy, and volume binding mode for each class.
Deploying Stateful Applications with Persistent Storage
A database pod using persistent storage through a PVC.
apiVersion: apps/v1
kind: Deployment
metadata:
name: postgres
spec:
replicas: 1
selector:
matchLabels:
app: postgres
template:
metadata:
labels:
app: postgres
spec:
containers:
- name: postgres
image: postgres:16
env:
- name: POSTGRES_DB
value: myapp
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
ports:
- containerPort: 5432
volumeMounts:
- name: postgres-data
mountPath: /var/lib/postgresql/data
volumes:
- name: postgres-data
persistentVolumeClaim:
claimName: postgres-pvc
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: postgres-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi
storageClassName: fast-ssd
# Deploy PostgreSQL with persistent storage
kubectl apply -f postgres-pvc.yaml
kubectl apply -f postgres-deployment.yaml
# Verify data persists across pod restarts
kubectl exec postgres-xxx -- psql -U postgres -c "CREATE TABLE test (id int);"
kubectl delete pod postgres-xxx
# Wait for new pod
kubectl exec postgres-yyy -- psql -U postgres -c "\dt"
Expected output: the new pod has the same data, proving persistence. The PVC remains Bound to the PV even after the pod is recreated.
StatefulSets and Stable Storage
StatefulSets provide stable network identities and ordered storage for each replica.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: kafka
spec:
serviceName: kafka-headless
replicas: 3
selector:
matchLabels:
app: kafka
template:
metadata:
labels:
app: kafka
spec:
containers:
- name: kafka
image: bitnami/kafka:3.6
ports:
- containerPort: 9092
volumeMounts:
- name: data
mountPath: /bitnami/kafka/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: fast-ssd
# Deploy the StatefulSet
kubectl apply -f kafka-statefulset.yaml
# Verify each pod gets its own PVC
kubectl get pvc
# Expected: data-kafka-0, data-kafka-1, data-kafka-2
# Check pod startup order
kubectl logs kafka-0
Expected output: three PVCs are created -- data-kafka-0, data-kafka-1, data-kafka-2 -- each bound to its own PV. Pods start and stop in ordinal order.
Practice Questions
What is the difference between ReadWriteOnce and ReadWriteMany access modes? ReadWriteOnce allows a single node to mount the volume as read-write. ReadWriteMany allows multiple nodes and pods to mount simultaneously, typically used with NFS or CephFS.
What happens to the PV when a PVC is deleted? The behavior depends on the reclaim policy -- Delete deletes the underlying storage, Retain keeps it for manual recovery, and Recycle scrubs it for reuse.
How does dynamic provisioning differ from static provisioning? Dynamic provisioning creates a PV automatically when a PVC requests a StorageClass. Static provisioning requires an administrator to pre-create PVs that PVCs can bind to.
Frequently Asked Questions
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro