The Problem with Deployments

A standard Deployment treats Pods as cattle. They are interchangeable. If `pod-abcde` dies, it is replaced by `pod-fghij`. They share no history, no identity, and no persistent storage unique to them.

1. The “Sticky Identity” Requirement

Databases (like MySQL, Cassandra, Kafka) need:

  1. Stable Network ID: “I am always db-0.”
  2. Stable Storage: “I always need disk-0 attached to me.”
  3. Ordered Startup: “Primary (db-0) must start before Replica (db-1).”

Enter the StatefulSet.


2. Interactive: StatefulSet Scaling Simulator

Watch how a StatefulSet scales compared to a Deployment. Notice the Ordering and Persistent Identity.

StatefulSet: web (Replicas=0)
$ Ready to scale.

3. Key Feature: VolumeClaimTemplates

In a Deployment, all Pods share the same PVC definition (usually creating a ReadWriteMany volume, or failing if ReadWriteOnce).

In a StatefulSet, you define a Template. Each Pod gets its own unique PVC stamped out from that template.

  • web-0 gets pvc-web-0
  • web-1 gets pvc-web-1

If web-0 dies and restarts, it reattaches to pvc-web-0. Data Persistence is guaranteed per replica.


4. Headless Service

A StatefulSet requires a Headless Service to control the network domain.

A normal Service has a ClusterIP and load balances traffic. A Headless Service (ClusterIP: None) returns the IPs of the individual Pods.

This allows web-0 to talk directly to web-1 by DNS name: web-1.service-name.default.svc.cluster.local.


5. Configuration Example

StatefulSet YAML
Service YAML
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx" # Must match Headless Service
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: k8s.gcr.io/nginx-slim:0.8
        volumeMounts:
        - name: www
          mountPath: /usr/share/nginx/html
  # The Magic: Auto-creates PVCs for each Pod
  volumeClaimTemplates:
  - metadata:
      name: www
    spec:
      accessModes: [ "ReadWriteOnce" ]
      storageClassName: "my-storage-class"
      resources:
        requests:
          storage: 1Gi
apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None  # HEADLESS!
  selector:
    app: nginx

6. When to use StatefulSets?

  • Databases: MySQL, PostgreSQL, MongoDB (Primary/Replica).
  • Clustered Apps: Zookeeper, Kafka, Elasticsearch.
  • Legacy Apps: Apps that write to local disk and expect it to be there after a restart.