CKAD field manual
k8s StatefulSet YAML example
A Deployment's Pods are interchangeable — any replica can die and come back with a new name, sharing one volume. A StatefulSet numbers them (web-0, web-1, ...), starts/stops them in order, and gives each its own PVC that survives a restart.
apiVersion: v1
kind: Service
metadata:
name: web
labels:
app: web
spec:
clusterIP: None
selector:
app: web
ports:
- port: 80
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: web
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27
ports:
- containerPort: 80
volumeMounts:
- name: data
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 1Gi
kubectl get sts web
kubectl get pods -l app=web -o wide
kubectl get pvc -l app=web
kubectl scale sts/web --replicas=5
kubectl rollout status sts/web
kubectl exec -it web-0 -- sh
kubectl delete sts web --cascade=orphan
kubectl get pods -l app=web
kubectl delete pvc -l app=web
Fields
- serviceName
- Must name a headless Service (clusterIP: None) in the same namespace. Gives each Pod a stable DNS name.
- volumeClaimTemplates
- One PVC per Pod, created automatically and named <template>-<pod>. Not shared like a Deployment's volume.
- podManagementPolicy
- OrderedReady (default) waits for each Pod to be Ready before starting the next. Parallel starts them all at once.
- updateStrategy
- RollingUpdate updates the highest ordinal first. partition holds back updates to Pods below that ordinal.
- selector
- Same rule as Deployment — selector.matchLabels must match template.metadata.labels, and it's immutable after create.
- clusterIP
- None makes the Service headless: DNS resolves to each Pod's own IP (<pod>.<svc>), not one shared virtual IP.
- kubectl scale sts
- Scales up by adding the next ordinal and waiting for it Ready. Scales down by removing the highest ordinal first.
- kubectl delete
- Deleting a StatefulSet does not delete its PVCs. Data outlives the Pods on purpose — delete PVCs yourself to actually remove it.
Watch
- There is no kubectl create statefulset. Write the YAML by hand, or dry-run a Deployment and change kind, add serviceName and volumeClaimTemplates.
- serviceName must point at a real headless Service (clusterIP: None) or Pod DNS never resolves.
- Deleting the StatefulSet does not delete its PersistentVolumeClaims. Delete them yourself if the task actually wants the data gone.
- Scaling down removes the highest ordinal first (web-2 before web-1). Scaling up waits for each new Pod Ready before starting the next (OrderedReady default).
Official docs StatefulSets