Deployment vs StatefulSet for PVCs in Kubernetes: Which One Should You Use (and When)?
DevOps engineer & developer passionate about building scalable, reliable systems. I design and automate pipelines, manage cloud infrastructure, and ensure deployments run smoothly. Turning complex workflows into seamless operations is my craft.
"One PVC to rule them all? Or one PVC per pod? The answer depends on how stateful your app really is."
The Tale of Two Pods: Nginx and MySQL
Once upon a time in the land of Kubernetes, there lived two pods — Nginx and MySQL.
Nginx was a stateless web server, fast and carefree. He didn’t worry about losing data — if he crashed, he’d just spin back up like nothing happened.
MySQL, on the other hand, was very stateful. She guarded her treasure — gigabytes of important data — and couldn’t afford to lose a single bit.
One day, both wanted a place to store their data, so they asked the Kubernetes King for help.
The king gave Nginx a simple Deployment with a shared PVC.
But for MySQL, he created a StatefulSet, with a personal storage room (PVC) for each pod, and a name that never changed — mysql-0, mysql-1.
And thus, each pod lived happily ever after:
Nginx, serving pages with speed,
MySQL, safely storing data without fear of losing identity.
And Kubernetes? It orchestrated their lives with ease.
The end.
Why PVCs Matter in Kubernetes
Kubernetes pods are ephemeral — they come and go. But your data should not.
This is where PVCs (PersistentVolumeClaims) come in. They let your pods store data outside themselves so it can survive restarts.
But how you attach that PVC depends on whether you're using a:
Deployment
StatefulSet
And that changes everything.
Quick Comparison: Deployment vs StatefulSet (for PVCs)
| Feature | Deployment | StatefulSet |
| Pod names | Random (nginx-66cbf) | Stable (nginx-0, nginx-1) |
| PVCs | Shared PVC for all pods | Unique PVC per replica |
| Ordered scaling | ❌ No | ✅ Yes |
| Use case | Web apps, frontend servers | DBs, Kafka, Elasticsearch |
| Dynamic PVC creation | ❌ Not supported | ✅ via volumeClaimTemplates |
Let’s See Them in Action!
Scenario 1: Deployment with PVC (Shared Storage)
You want 2 NGINX replicas sharing HTML files from a volume.
Step 1: Create the PVC
# shared-pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: shared-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: standard
Step 2: Deploy with Shared PVC
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: shared-volume
mountPath: /usr/share/nginx/html
volumes:
- name: shared-volume
persistentVolumeClaim:
claimName: shared-pvc
Warning: Only one pod can mount a
ReadWriteOncevolume at a time. The second pod may fail.If you use
ReadOnlyManyorReadWriteMany(like NFS or GlusterFS), both pods can mount it.
Scenario 2: StatefulSet with PVC (Per-Pod Storage)
You’re deploying MySQL or Redis — each pod needs its own storage.
Step 1: Create a Headless Service
# headless-svc.yaml
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
Step 2: StatefulSet with volumeClaimTemplates
# mysql-statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: "mysql"
replicas: 2
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
ports:
- containerPort: 3306
env:
- name: MYSQL_ROOT_PASSWORD
value: "mypassword"
volumeMounts:
- name: mysql-storage
mountPath: /var/lib/mysql
volumeClaimTemplates:
- metadata:
name: mysql-storage
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "standard"
resources:
requests:
storage: 1Gi
This automatically creates:
mysql-storage-mysql-0for podmysql-0
mysql-storage-mysql-1for podmysql-1
Test It
To check the PVCs created:
kubectl get pvc
For StatefulSet:
mysql-storage-mysql-0 Bound
mysql-storage-mysql-1 Bound
For Deployment (only one shared):
shared-pvc Bound
Summary: Deployment vs StatefulSet for PVCs
| Criteria | Deployment | StatefulSet |
| Shared PVC | ✅ Easy | ❌ Not ideal |
| Unique PVC per pod | ❌ Not possible | ✅ Auto-generated |
| Scale safely | ❌ Risk of volume mount errors | ✅ Safe scaling |
| DNS & identity | ❌ Random | ✅ Stable |
| Production DBs | ❌ No | ✅ Yes |
Conclusion
Kubernetes makes storage powerful and flexible, but knowing when to use Deployment vs StatefulSet for PVCs is key:
Use Deployment when:
Your pods can share data
You don’t need persistent identity
Use StatefulSet when:
You need one volume per replica
You're running DBs, caches, or distributed systems