StatefulSet

A StatefulSet is a Kubernetes controller that manages the deployment and scaling of a set of Pods with unique, stable identities and persistent storage.

It’s used for stateful applications such as:

  • Databases (MySQL, PostgreSQL, MongoDB)

  • Distributed systems (Cassandra, Kafka, Zookeeper)

  • Anything requiring stable Pod names, stable storage, or ordered startup/shutdown

Stable storage

  • Each Pod can get its own PersistentVolumeClaim (PVC), automatically created by the StatefulSet.

  • The storage is bound to the Pod’s identity (mydb-0 always uses pvc-mydb-0).

  • Even if the Pod is rescheduled on another node, it reattaches to the same storage.

Ordered, graceful deployment and scaling

  • Pods are created one by one, in order (mydb-0, then mydb-1, then mydb-2).

  • Similarly, they are deleted in reverse order.

  • Useful when apps require strict initialization order (like primary DB before replicas).

Rolling updates

  • StatefulSets support rolling updates, but they also ensure ordering and readiness at each step.

  • This prevents breaking distributed systems during upgrades.

Commands

To apply and run a StatefulSet configuration:

kubectl apply -f statefulset.yaml

To list the StatefulSets:

kubectl get statefulsets

To describe a StatefulSet:

kubectl describe statefulset <statefulset-name>

To delete a StatefulSet:

kubectl delete statefulset <statefulset-name>

To update image through the CLI:

kubectl set image statefulset/<statefulset-name> nginx=nginx:1.25

To get the rollout history of StatefulSets:

kubectl rollout history statefulset <statefulset-name>

To rollback a StatefulSet to a previous version:

kubectl rollout undo statefulset <statefulset-name>

# To a specific revision number
kubectl rollout undo statefulset <statefulset-name> --to-revision=<rev-number>

To scale StatefulSets:

kubectl scale statefulset <statefulset-name> --replicas=5

Check consumption of a StatefulSet:

kubectl top statefulset <statefulset-name>

In this example, the Headless Service provides DNS por Pods and StatefulSet creates Pods with stable names.

Each Pod gets its own PVC.

headless-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp-headless-service
spec:
  clusterIp: None   # headless service
  selector:
    app: myapp-stateful
  ports:
    - port: 3306
      name: myapp-container
statefulset.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: myapp-stateful
spec:
  serviceName: myapp-headless-service
  replicas: 3
  selector:
    matchLabels:
      app: myapp-container
  # Pod template
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
        - name: myapp-container
          image: mysql
          ports:
            - containerPort: 3306
          env:
            ...
          volumeMounts:
            - name: myapp-container-data
              mountPath: /var/lib/mysql
  volumeClaimTemplates:
    - metadata:
        name: myapp-container-data
      spec:
        accessNodes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 10Gi

Last updated