A StatefulSet is the Kubernetes workload controller for stateful applications: it manages a set of Pods that each keep a stable, unique identity, a predictable DNS name and their own persistent storage across restarts and rescheduling. In Kubernetes, StatefulSets are the standard way to run databases, message brokers and distributed coordination systems whose members are not interchangeable.
Where a Deployment treats Pods as identical and disposable, a StatefulSet treats them as numbered members of a group: db-0, db-1, db-2. If db-1 is replaced, the new Pod gets the same name, the same network identity and the same volume, so the application can resume its role in the cluster.
How a StatefulSet maintains Pod identity
A StatefulSet gives each Pod an ordinal index from 0 to N-1 and builds every identity attribute from it. The controller ensures that at most one Pod with a given identity exists at any time, which is essential for systems that elect leaders or replicate data by member name.
| Attribute | Example | How it is provided |
|---|---|---|
| Pod name | db-0, db-1, db-2 | StatefulSet name plus ordinal |
| DNS name | db-0.db.prod.svc.cluster.local | Headless Service named in serviceName |
| Persistent volume | PVC data-db-0 | volumeClaimTemplates, one claim per Pod |
| Hostname | db-0 | Set inside the container |
Stable DNS requires a headless Service (a Service with clusterIP: None) referenced by the StatefulSet. It creates a DNS record for each Pod rather than a single load-balanced address, so clients and peers can contact a specific member, for example the current primary database.
Storage identity comes from volumeClaimTemplates. For each ordinal, the controller creates a PersistentVolumeClaim, and a rescheduled Pod reattaches to that same claim, even on another node, provided the storage class supports it.
Identity is sticky but not tied to a node. If the node hosting db-1 is drained, the Pod is recreated elsewhere with the same name, DNS record and claim. Only the Pod IP address changes, which is why clients should always connect through the stable DNS name rather than a cached IP.
Ordering, scaling and update strategies
By default a StatefulSet uses the OrderedReady pod management policy: Pods start one at a time in ascending order, each waiting until the previous one is Running and Ready, and they terminate in reverse order when scaling down. This matches the bootstrap needs of many clustered systems.
| Setting | Options | Effect |
|---|---|---|
| podManagementPolicy | OrderedReady or Parallel | Sequential or simultaneous Pod creation |
| updateStrategy | RollingUpdate or OnDelete | Automatic or manual Pod replacement on change |
| partition | Integer ordinal | Only Pods at or above it are updated, for canaries |
| persistentVolumeClaimRetentionPolicy | Retain or Delete, on deletion and scale-down | Whether PVCs survive |
| minReadySeconds | Seconds | Time a Pod must stay ready before counting |
A rolling update replaces Pods from the highest ordinal down to zero, one at a time. Setting a partition lets operators update only the top members first and observe them, which is a simple canary mechanism for stateful systems.
The Parallel policy is useful when members do not depend on each other during startup, for example in a sharded cache, because it shortens scaling time considerably. It changes only creation and deletion order; rolling updates still proceed one Pod at a time.
StatefulSet compared with Deployment and DaemonSet
The choice of workload controller follows from whether Pods are interchangeable. Stateless web services fit a Deployment; per-node agents fit a DaemonSet; members that carry data and identity need a StatefulSet.
| Controller | Pod identity | Storage | Typical workload |
|---|---|---|---|
| StatefulSet | Stable names and ordinals | One PVC per Pod | Databases, Kafka, ZooKeeper, etcd |
| Deployment | Random names, interchangeable | Usually shared or none | Web servers, APIs |
| DaemonSet | One Pod per node | Usually node-local | Log shippers, monitoring agents |
| ReplicaSet | Random names | None by design | Managed by Deployments |
A StatefulSet does not make an application highly available or replicated by itself. It only provides stable identity and storage; replication, failover and data consistency must still be implemented by the database or by an operator that manages it.
Running databases with StatefulSets
Running production data stores on StatefulSets is common, but it requires careful attention to storage, scheduling and lifecycle. Many teams use a Kubernetes operator that wraps a StatefulSet and adds database-specific logic such as failover, backups and version upgrades.
| Area | Recommended practice | Reason |
|---|---|---|
| Storage class | Replicated or zone-aware volumes | Pods can move without losing data |
| Pod anti-affinity | Spread members across nodes and zones | One failure does not take several members |
| PodDisruptionBudget | Allow at most one member down | Keeps quorum during node maintenance |
| Probes | Readiness reflects real replication health | Ordered rollout stops on bad members |
| Backups | Independent of the cluster | PVCs are not backups |
Graceful termination matters for databases. A sufficiently long terminationGracePeriodSeconds lets the process flush data and hand over leadership before Kubernetes kills it.
Pitfalls and failure behavior
StatefulSets favor safety over availability when a node becomes unreachable. Kubernetes does not automatically start a replacement Pod with the same identity while the old one might still be running, because two copies writing to the same data could corrupt it.
- Assuming PVCs are deleted with the StatefulSet; by default they are retained and keep costing storage.
- Force-deleting Pods on an unreachable node, which can create two members with the same identity.
- Forgetting the headless Service, so per-Pod DNS names do not resolve.
- A broken rolling update that leaves a failing Pod, which may need manual deletion after reverting the template.
- Scaling down without data migration, which removes members that still hold unique data.
Changing many fields of volumeClaimTemplates after creation is not supported; resizing volumes or changing storage classes usually requires a planned migration.
Explained without jargon
A StatefulSet is like a team with fixed jersey numbers and personal lockers. Player 0, player 1 and player 2 each have their own locker with their own equipment.
If a player leaves the field and a substitute comes in, the substitute takes the same number and the same locker. Nothing gets mixed up. That is what databases need. The key idea is that each member keeps its name and its data.
A typical use case
A company runs a three-member PostgreSQL cluster in Kubernetes for an internal application. It uses a StatefulSet with three replicas, a headless Service and a volumeClaimTemplate requesting 200 GiB of SSD-backed storage per member. A database operator manages replication, with pg-0 starting as primary.
Pod anti-affinity spreads the members across three availability zones, and a PodDisruptionBudget allows only one member to be unavailable. When a node in one zone is drained for an upgrade, pg-2 stops, its volume is reattached on a new node and the Pod returns under the same name.
During a later version upgrade, the team sets the partition to 2, updates only pg-2, checks replication and then lowers the partition step by step. The upgrade completes without data loss and the application stays available.