What is a StatefulSet and why is it needed for databases instead of a Deployment?
Quick Answer
A StatefulSet provides stable network identities (pod-0, pod-1, pod-2), persistent storage that follows each pod across rescheduling, and ordered startup/shutdown. Databases need these guarantees because replicas have distinct roles (primary vs replica), each needs its own persistent volume, and initialization order matters for replication setup.
Detailed Answer
Think of the difference like assigned seating versus general admission at a concert. A Deployment is general admission -- you get 5 seats somewhere, and if you leave and come back, you might get different seats. A StatefulSet is assigned seating -- seat 1 is always seat 1 with the same person, same view, same neighbors, and if you step out for a snack, your seat is reserved when you return. Databases need assigned seating because each instance has a specific role and its own data.
A StatefulSet provides three guarantees that Deployments do not: (1) Stable, unique network identifiers -- pods are named deterministically (postgres-0, postgres-1, postgres-2) rather than randomly (postgres-7d4f8b-x9k2p). Each pod gets a DNS record via a headless Service (postgres-0.postgres-headless.database.svc.cluster.local) that persists across pod rescheduling. (2) Stable, persistent storage -- each pod gets its own PVC through volumeClaimTemplates, and that specific PVC reattaches to the same pod if it restarts. Pod postgres-0 always gets PVC data-postgres-0, even after deletion and recreation. (3) Ordered, graceful operations -- pods are created sequentially (0, then 1, then 2) and terminated in reverse order (2, then 1, then 0).
For databases, these guarantees are essential. Consider a PostgreSQL cluster with primary-replica replication: postgres-0 is the primary (accepts writes), postgres-1 and postgres-2 are replicas (stream WAL from primary). The replicas are configured to connect to postgres-0.postgres-headless for replication. If postgres-0 were a Deployment pod with a random name, every time it restarted with a new name, all replicas would lose their replication source. With a StatefulSet, postgres-0 always comes back as postgres-0 with the same DNS name and the same data volume, so replicas automatically reconnect.
Ordered startup matters for initialization: postgres-0 must be running and initialized before postgres-1 can start streaming WAL from it. StatefulSets guarantee this ordering by default (though you can use podManagementPolicy: Parallel to opt out for services that don't need it). Similarly, during scale-down, the highest-ordinal pod is removed first -- you never accidentally delete the primary (ordinal 0) before the replicas.
In production, StatefulSets have operational trade-offs: they are slower to recover from node failures because of the at-most-one semantics (the controller will not create a replacement pod until it can confirm the old one is fully terminated and its volume is detached). They are harder to debug because you cannot simply delete a stuck pod and let a fresh one take over -- the replacement must be the same ordinal with the same volume. Rolling updates proceed one pod at a time in reverse ordinal order by default, making them slower than Deployments. These trade-offs are acceptable for stateful workloads where data consistency matters more than recovery speed.