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.

A walker in a jungle carries its own docked pack. A walker in a neon jungle carries its own docked pack.
Headless Service + StatefulSet
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
Inspect and scale
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
Delete without losing data
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

Practice these objects on a live cluster →