Skip to main content
reliability · kubernetes

StatefulSets with unready replicas blocking the rollout

resource types
1
rule IDs covered
3
severity
high

What does ZopNight detect here?

A StatefulSet short of its desired replicas is worse than a Deployment in the same state. Pods start in strict ordinal order, so 1 stuck pod halts every pod after it. Ordinal 3 failing means 4 and above never start at all, indefinitely.

Signal and threshold

How ZopNight evaluates StatefulSets with unready replicas blocking the rollout.
Field Value
Rule IDsRC-1715 · RC-1815 · RC-1915
Categoryreliability
Severityhigh
Metricnone — pure configuration read
Sourceinternal/rules/k8s/statefulset_degraded.go

Ordered startup turns one failure into a stall

This is the property that separates a StatefulSet from a Deployment, and it is why the same symptom is more serious here.

With the default OrderedReady policy, pod N+1 is not created until pod N is Running and Ready. A StatefulSet of five whose ordinal 2 cannot become ready never creates 3 or 4. It does not degrade to three-fifths capacity and continue. It stops.

The controller waits indefinitely. There is no timeout, no fallback, and no event that says “blocked”.

Rollouts stall the same way, in reverse

Updates proceed from the highest ordinal downwards, one at a time. A new pod that fails readiness halts the rollout where it stands, leaving the StatefulSet split across two versions.

That is safer than a Deployment charging ahead, but it means a bad image can leave you with ordinals 3 and 4 on the new version and 0 through 2 on the old, potentially for hours, with whatever consistency implications that carries for your application.

Storage is the usual culprit

StatefulSets bind a PersistentVolumeClaim per ordinal, and those claims are where the blocking tends to originate: a PVC stuck Pending, a volume in the wrong availability zone for the node the pod must run on, or a StorageClass quota reached mid-scale-up.

Deleting the pod does not help. It comes back with the same claim, into the same problem.

Parallel policy changes the trade

podManagementPolicy: Parallel starts all pods at once, so one failure no longer blocks the rest. It also discards the ordering guarantee, which for a database with a defined bootstrap sequence is exactly the guarantee you wanted.

Change it deliberately, not to clear a finding.

Ready ordinals, then the PVC of the lowest one

Terminal window
kubectl get statefulset -A -o json | jq -r '
.items[] | select((.status.readyReplicas // 0) < .spec.replicas)
| "\(.metadata.namespace)/\(.metadata.name)\t\(.status.readyReplicas // 0)/\(.spec.replicas)"'

Then find the lowest unready ordinal, the one blocking everything above it, and check its PVC before anything else.

See it fire on your bill.

Connect an account read-only. The first findings land in minutes.

417 rule families across 353 resource types on 22 platforms. Every threshold, metric, and IAM action is documented on these pages before you grant anything.

417 rule families documented
353 resource types covered
read-only default access level
Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console· Multi-cloud automation· Production-ready in 30 min· SOC 2 · ISO 27001· 20–60% off the bill, first month· 4 platforms · 1 console·