Skip to content
Lucas Mauro

What is a Kubernetes StatefulSet?

How does it differ from a Kubernetes Delpoyment?

kubernetes 2 min read

A StatefulSet is a Kubernetes object designed for stateful applications. Unlike a Deployments, which treats all pods as interchangeable, a StatefulSet gives each pod a stable identity and persistent storage. This ends up being essential for applications that need to remember who they are and, perhaps most importantly, where their data lives (e.g. databases, message queues, distributed caches, and so on).

A deployment creates pods with random names (e.g. nginx-deployment-7fb94c8f4-x2jkl) and assigns them ephemeral storage. If a pod is replaced, it gets a new name and a fresh disk. For stateless applications, this is perfectly fine. For a database, however, losing its name and data on every reschedule would be a problem.

StatefulSet solves this by guaranteeing us with:

  • Stable, unique pod names: pods get predictable names like db-0, db-1, db-2 instead of random suffixes;
  • Stable network identities: each pod gets a consistent DNS entry that follows the pattern <pod-name>.<service-name>.<namespace>.svc.cluster.local;
  • Persistent storage: each pod gets its own PersistentVolumeClaim, which survives pod reschedules and restarts.

apiVersion: apps/v1
kind: StatefulSet
metadata:
name: db
spec:
serviceName: 'db-service'
replicas: 3
selector:
matchLabels:
app: db
template:
metadata:
labels:
app: db
spec:
containers:
- name: db
image: postgres:16
ports:
- containerPort: 5432
volumeMounts:
- name: data
mountPath: /var/lib/postgresql/data
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ['ReadWriteOnce']
resources:
requests:
storage: 10Gi

Let’s have a closer look:

  • serviceName links the StatefulSet to a headless Services, which is required for stable DNS entries (more on this below);
  • replicas works the same way as in a deployment (3 pods in this case);
  • template is the pod template, identical to what we’d see in a deployment;
  • volumeClaimTemplates is what makes StatefulSets special: it creates a separate PersistentVolumeClaim for each pod, so db-0, db-1, and db-2 each get their own 10Gi volume.

For the stable DNS entries to work, a StatefulSet needs a headless service (a service with clusterIP: None). A headless service does not perform load balancing; instead, it returns the IP addresses of individual pods directly.

apiVersion: v1
kind: Service
metadata:
name: db-service
spec:
clusterIP: None
selector:
app: db
ports:
- port: 5432

With this in place, db-0.db-service.default.svc.cluster.local always resolves to the pod named db-0, regardless of which node it is running on.

When we scale a StatefulSet up, Kubernetes creates pods in order (db-3, then db-4, and so on). When we scale down, it removes pods in reverse order (db-4, then db-3). This ordered approach is important for distributed systems that rely on peer discovery (each node knows its neighbours by name).

DeploymentsStatefulSets
Pod namesRandomStable and ordered
StorageEphemeral (unless explicitly configured)Persistent, per pod
ScalingOrder does not matterPods created and removed in order
Best forStateless appsDatabases, queues, anything with state

Comments