A Deployment rolls a new template out through a new ReplicaSet. A StatefulSet has no ReplicaSets and no random Pods; it updates the ones it has, in order.
Reverse ordinal
learner@shallows:~$ kubectl set image sts/db postgres=postgres:16.2
statefulset.apps/db image updatedThe highest ordinal goes first and each Pod must be Ready before the next is replaced. kubectl rollout status sts db watches it. Each Pod keeps its name and its claim across the update.
Partition
spec.updateStrategy.rollingUpdate.partition holds the update back: only Pods with an ordinal greater than or equal to the partition are updated.
| Replicas | Partition | Updated |
|---|---|---|
| 3 | 3 | None |
| 3 | 2 | db-2 only |
| 3 | 0 | All |
That is a canary. Set the partition to the replica count, change the image, lower the partition by one and watch the single updated Pod, then lower it to 0:
learner@shallows:~$ kubectl patch sts db -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'A StatefulSet whose template has changed but whose Pods have not is often just a partition someone forgot. kubectl get sts db -o jsonpath='{.spec.updateStrategy}' shows it.
Delete and recreate
kubectl delete sts db deletes the Pods and keeps the claims. Apply the same manifest again: db-0 finds data-db-0, and so on. The data was never in the StatefulSet; it was in the claims. Delete with --cascade=orphan and even the Pods stay.