StatefulSets

A StatefulSet manages stateful apps that need stable identities and persistent storage per Pod.

Deployments treat Pods as interchangeable. But databases and other stateful apps need each Pod to keep its identity and its own disk. That is the job of a StatefulSet.

What it guarantees

  • Stable names — Pods are named predictably: db-0, db-1, db-2.
  • Stable storage — each Pod gets its own PersistentVolume that survives restarts.
  • Ordered operations — Pods start and stop one at a time, in order.

Headless Service

StatefulSets pair with a headless Service (clusterIP: None) that gives each Pod a stable DNS name like db-0.db.default.svc.cluster.local, so peers can find one another.

Example

Example · yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: db
spec:
  serviceName: db
  replicas: 3
  selector:
    matchLabels:
      app: db
  template:
    metadata:
      labels:
        app: db
    spec:
      containers:
        - name: postgres
          image: postgres:16
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 5Gi

When to use it

  • A database team runs a three-node MySQL cluster as a StatefulSet so each pod gets a stable hostname (mysql-0, mysql-1, mysql-2) for replica configuration.
  • A Kafka operator uses a StatefulSet to ensure each broker's persistent volume is reattached to the same pod after a restart, preserving broker data.
  • An ops team scales down a StatefulSet one pod at a time (in reverse ordinal order) to safely drain Cassandra ring nodes before decommissioning.

More examples

StatefulSet for a database cluster

Defines a 3-replica MySQL StatefulSet with per-pod PersistentVolumeClaims so each instance retains its own data volume.

Example · yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
spec:
  serviceName: mysql-headless
  replicas: 3
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
        - name: mysql
          image: mysql:8.0
          env:
            - name: MYSQL_ROOT_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: mysql-secret
                  key: password
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ReadWriteOnce]
        resources:
          requests:
            storage: 10Gi

Stable DNS names per pod

Shows the stable, predictable pod DNS names provided by the headless Service, enabling replicas to discover each other.

Example · bash
kubectl get pods -l app=mysql
# mysql-0, mysql-1, mysql-2

# Each pod is reachable at:
# mysql-0.mysql-headless.default.svc.cluster.local
# mysql-1.mysql-headless.default.svc.cluster.local

Ordered scale-down

Demonstrates that StatefulSets scale down in reverse ordinal order, protecting data integrity in clustered databases.

Example · bash
kubectl scale statefulset mysql --replicas=2
# Kubernetes deletes mysql-2 first, then mysql-1 if reducing further
# Ensures orderly Cassandra/Kafka decommissioning

Discussion

  • Be the first to comment on this lesson.