Repository navigation
EN_CS_StatefulSet
somaz edited this page Sep 22, 2026
·
4 revisions
Question: Explain the difference between Stateful applications (StatefulSet) and Stateless applications, and how each is deployed and scaled in Kubernetes. Focus on the role of Persistent Volumes, Headless Services, and stable Pod identifiers.
| Term | Description |
|---|---|
| StatefulSet | Kubernetes object that manages applications with state |
| Stateless Application | Application that keeps no internal state and handles each request independently |
| Headless Service | Service whose ClusterIP is None — returns Pod IPs directly |
| Ordinal Index | Ordinal number of a StatefulSet Pod (pod-0, pod-1, pod-2) |
| PVC (PersistentVolumeClaim) | Object through which a Pod requests a PV |
| volumeClaimTemplates | Template that automatically creates a PVC for each Pod in a StatefulSet |
Stateless (Deployment): Stateful (StatefulSet):
┌──────┐ ┌──────┐ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│Pod A │ │Pod B │ │Pod C │ │ mysql-0 │ │ mysql-1 │ │ mysql-2 │
│ │ │ │ │ │ │ (Master) │ │ (Slave) │ │ (Slave) │
└──────┘ └──────┘ └──────┘ │ PV-0 │ │ PV-1 │ │ PV-2 │
↓ └──────────┘ └──────────┘ └──────────┘
Shared Database └─────── Replication ──────┘
(External State)
| Aspect | Stateless (Deployment) | Stateful (StatefulSet) |
|---|---|---|
| Pod Name | Random (nginx-abc123) | Ordinal (mysql-0, mysql-1) |
| Creation Order | Can be created simultaneously | Sequential creation (0 → 1 → 2) |
| Deletion Order | Can be deleted simultaneously | Reverse-order deletion (2 → 1 → 0) |
| Network Identity | Unstable (Pod IP changes) | Stable (DNS preserved) |
| Storage | Shared or none | PVC per Pod |
| Service Type | ClusterIP / LoadBalancer | Headless + ClusterIP |
| Use Cases | Web servers, API servers | DBs, messaging, distributed storage |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"Rolling Update:
-
maxSurge: 1→ allows up to replica+1 Pods running at the same time -
maxUnavailable: 0→ always keeps the replica count (zero downtime)
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless # Headless Service required
replicas: 3
selector:
matchLabels:
app: mysql
template:
spec:
containers:
- name: mysql
image: mysql:8.0
volumeMounts:
- name: mysql-data
mountPath: /var/lib/mysql
volumeClaimTemplates: # Auto-creates a PVC per Pod
- metadata:
name: mysql-data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: gp3
resources:
requests:
storage: 10GiSetting clusterIP: None returns Pod IPs directly, without a VIP.
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306DNS lookup result:
mysql-headless → 10.244.1.10 (mysql-0)
→ 10.244.2.20 (mysql-1)
→ 10.244.3.30 (mysql-2)
Per-Pod DNS:
mysql-0.mysql-headless.default.svc.cluster.local → 10.244.1.10
mysql-1.mysql-headless.default.svc.cluster.local → 10.244.2.20
DNS names persist even after a Pod restart → Master/Slave can be addressed directly.
- Deleting a StatefulSet does not delete the PVCs (data is preserved)
- When a Pod is recreated, the existing PVC is reused
- PVCs must be deleted manually:
kubectl delete pvc mysql-data-mysql-0
Volume expansion (requires allowVolumeExpansion: true in the StorageClass):
kubectl patch pvc mysql-data-mysql-0 \
-p '{"spec":{"resources":{"requests":{"storage":"20Gi"}}}}'| Strategy | Behavior |
|---|---|
| RollingUpdate (default) | Sequential update in reverse order (mysql-2 → mysql-1 → mysql-0) |
| OnDelete | No automatic update; a Pod is recreated with the new version when manually deleted |
To create and delete all Pods at once without ordering, use the separate field
podManagementPolicy: Parallel(defaultOrderedReady), not an update strategy.