KubernetesXVII · StatefulSetsStatefulSets
Ordered deployment and the partition field — controlling rollout sequence
What you'll learn
- Describe the create-in-order and delete-in-reverse-order lifecycle of StatefulSet Pods
- Use the `partition` field to stage rollouts across ordinals
- Reason about the operational cost of ordered deployment for clustered workloads
- Diagnose a stuck ordinal that blocks scaling
Prerequisites
Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16
The ordered lifecycle is the StatefulSet’s most distinctive
feature and its most common operational hazard. Pods are
created 0, 1, 2, ... and deleted n-1, n-2, ..., 0. The
controller waits for each Pod to be Ready before creating the
next. A bad configuration that prevents one ordinal from
becoming Ready blocks every later ordinal, and the
StatefulSet appears “stuck” with no obvious cause.
Ordered creation
sequenceDiagram
participant K as StatefulSet controller
participant P0 as postgres-0
participant P1 as postgres-1
participant P2 as postgres-2
Note over K: replicas: 0 -> 3
K->>P0: create
P0->>K: Pending
P0->>K: ContainerCreating
P0->>K: Running, Ready=True
K->>P1: create
P1->>K: Pending
P1->>K: ContainerCreating
P1->>K: Running, Ready=True
K->>P2: create
P2->>K: Running, Ready=True
Note over K: replicas: 3 ready
Each Pod waits for the previous ordinal to be Ready. The controller does not parallelise creation across ordinals.
The reason is correctness: clustered software’s bootstrap logic typically relies on the first ordinal being the primary (or some other seed) and the rest joining the cluster. If the controller spawned all ordinals simultaneously, the “first to start” race would be non-deterministic.
Ordered deletion
Deletion runs in reverse ordinal order: highest ordinal first.
sequenceDiagram
participant K as StatefulSet controller
participant P0 as postgres-0
participant P1 as postgres-1
participant P2 as postgres-2
Note over K: replicas: 3 -> 0
K->>P2: delete
P2->>K: Terminating
P2->>K: gone
K->>P1: delete
P1->>K: gone
K->>P0: delete
P0->>K: gone
Note over K: 0 ready
Reverse order means the cluster’s primary (typically ordinal 0) is the last to go. The replicas are removed first, the primary last. This gives the workload a chance to drain the cluster cleanly.
The partition field for staged rollouts
spec.updateStrategy.rollingUpdate.partition controls how
many Pods get the new template during a rolling update. With
partition: 1 and replicas: 3, only ordinals ≥ 1 are
updated; ordinal 0 keeps the old template.
spec:
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 1
The use case: a release engineer wants to update
postgres-2 first (a non-primary replica), observe it, then
update postgres-1, then postgres-0 (the primary) last.
The partition lets the operator sequence the rollout by
hand:
flowchart LR
A["partition: 3<br/>no ordinals updated"] --> B["partition: 2<br/>only postgres-2"]
B --> C["partition: 1<br/>postgres-2 and postgres-1"]
C --> D["partition: 0<br/>all ordinals updated"]
$ kubectl patch statefulset postgres -n data --type=merge -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'statefulset.apps/postgres patched$ kubectl rollout status statefulset/postgres -n dataWaiting for ordinals [2] to be ready
waiting for statefulset rolling update to complete 2 out of 3 new pods updated...A partition smaller than the previous step is a rollback operation (re-apply the old template to the previously updated ordinals).
Failure modes
Stuck ordinal
A Pod that never becomes Ready blocks every subsequent ordinal. Causes:
flowchart TB
A[Stuck ordinal] --> B{Image pull<br/>failure?}
A --> C{Readiness probe<br/>failing?}
A --> D{PVC not bound?}
A --> E{Init container<br/>hangs?}
A --> F{Resource quota<br/>exhausted?}
Each one is diagnosable with kubectl describe pod and
kubectl logs. A failure to find any of these after the
usual checks usually points to application-level bootstrap
failure — the container is Running but not Ready because the
application’s own readiness check (e.g., the PostgreSQL
cluster replication check) is failing.
Headless Service missing
The StatefulSet references a headless Service in
serviceName. If that Service is missing, the StatefulSet’s
Pods fail DNS resolution and the application’s bootstrap cannot
find peers. The Pods appear Running but stuck.
Wrong PVC access mode
A StatefulSet’s PVC with ReadWriteOnce cannot be mounted on
two nodes. If the StatefulSet tries to schedule ordinals that
land on the same node, the second Pod’s volume mount fails.
This is rare with podAntiAffinity but does happen with small
clusters.
Update with bad template
A template change that breaks the application — wrong env,
broken readiness probe, missing ConfigMap — affects only the
updated ordinals. With partition: 0, all ordinals update.
The operator must kubectl edit the StatefulSet to revert,
but the controller will not apply the old template
automatically; the operator must kubectl apply the
manifest with the old template and observe the rollout
revert.
Why ordered is necessary
The cluster bootstrap is the answer. A replicated database cluster needs a known starting topology:
- PostgreSQL primary + replicas. Replica 1 connects to
the primary (
postgres-0); replica 2 joins the cluster. If both replicas start simultaneously, neither knows which is primary. - ZooKeeper ensemble. Each member needs the full member
list. Orderly startup ensures the first member sees a
single-member ensemble, the second sees
{1, 2}, the third sees{1, 2, 3}. The leader election is consistent at each step. - Kafka brokers. Each broker’s
cluster.idis shared across the ensemble, but the broker’sbroker.idis ordinal-specific. Sequential startup avoids racing on topic-partition leadership.
A Deployment, by contrast, has no ordering and is designed for stateless workloads. The choice of controller is the choice of semantics.
Inspecting the order
kubectl get pods -l app=postgres -n data -o custom-columns=\
NAME:.metadata.name,ORDINAL:.metadata.labels.statefulset\.kubernetes\.io/pod-name,READY:.status.conditions[?(@.type=="Ready")].status,AGE:.metadata.creationTimestamp
flowchart LR
A["StatefulSet controller<br/>reconcile loop"] --> B{desired replicas<br/>match current?}
B -->|no, scale up| C["Create next ordinal<br/>wait for Ready"]
B -->|no, scale down| D["Delete highest ordinal<br/>wait for gone"]
B -->|yes| E{updateStrategy<br/>needs update?}
E -->|yes| F["Update ordinals<br/>≥ partition"]
E -->|no| G[Idle until next reconcile]
Quiz
Knowledge check · 4 questions
Q1. In what order does a StatefulSet delete its Pods?
Q2. The partition field in a StatefulSet's updateStrategy allows you to update only Pods with ordinal >= partition.
Q3. Your team scales a StatefulSet from 3 to 5 replicas. Pod postgres-3 is created but never becomes Ready. Diagnose.
StatefulSet postgres has replicas 5. Pods postgres-0, postgres-1, postgres-2 are Ready. postgres-3 is Pending. PVC data-postgres-3 is Pending. The StorageClass provisioner is slow.
Q4. Why does a stuck ordinal in a StatefulSet block every later ordinal?
Passing score: 75%. Answers are checked in this browser.
Production discipline
- The partition field is your rollout knob. Use it for every production StatefulSet release; do not update all ordinals at once.
- Test the bootstrap path. A new ordinal must join the
cluster from cold. Run
kubectl scale statefulset postgres --replicas=4in staging; verify the new replica joins. - Runbook the rollback.
kubectl apply -fwith the old template andpartition: 0is the rollback path. The partition knob is the difference between a canary and a full outage. - Monitor Ready replicas per ordinal.
kube_statefulset _replicasandkube_statefulset_status_replicas_currentare the metrics; alerts should fire onstatus_replicas_ready != spec_replicas. - Avoid ordering-sensitive configuration. A broken readiness probe is worse on a StatefulSet than on a Deployment because the stuck ordinal blocks scaling.
Ordered deployment is the StatefulSet’s defining feature. Operators who understand it can run Postgres, Kafka, and ZooKeeper in production. Operators who do not understand it will lose data when the ordinal they did not realise mattered gets stuck.