Skip to main content

Kubernetes 1.37's StatefulSet Recreate Strategy (Alpha): Stop Deleting Stuck Pods by Hand

8 min readDora NodaDora Noda
Share
On this page

It is 2 a.m., and a tenant's database rollout is stuck. Somebody pushed a StatefulSet update with a typo in the image tag. The new pod sits in ImagePullBackOff. Somebody else already fixed the typo — and nothing happened. The controller is still waiting on the broken pod, the rollout is halted behind it, and the documented recovery procedure is you, deleting pods by hand in reverse ordinal order, hoping nobody edits the template again while you do it.

Here is the verdict up front. Kubernetes 1.37 ("Garhwal", August 2026) adds a third StatefulSet update strategy, Recreate, currently in alpha behind the StatefulSetRecreateStrategy feature gate. Set updateStrategy.type: Recreate and the controller stops waiting on corpses: on the next template change it deletes every old-revision pod and rebuilds from the current template — no ordinal-by-ordinal surgery, no wedged mixed-revision state. The price is explicit and non-negotiable: every pod goes down at once, so this strategy is not for production tenant databases yet. It is for everything around them.

One naming note before we go further, because it will confuse you in the tracker: the enhancement issue is still titled "Add EnforcedRollingUpdate" (KEP-3541, opened 2022). During review the proposal was reworked — instead of a flag bolted onto rolling updates, SIG Apps shipped a separate Recreate strategy, consistent with the one Deployments have had for years. There is no enforcedRollingUpdate field. If you go looking for the flag, you will not find it; the strategy is what landed.

The two ways a rollout wedges

StatefulSet's default RollingUpdate with OrderedReady follows a strict loop, spelled out in KEP-3541: walk ordinals from highest to lowest, and for each pod, wait until it is Running and Ready before touching the next one. That strictness is the whole point for stateful workloads — until a pod never becomes Ready. Then the loop does exactly what it was written to do: it waits. Forever.

Wedge shape 1: the broken config. A typo in the image name, a resource limit no node can satisfy, a secret that does not exist. Pod app-4 fails, the update halts, and here is the part that breaks automation: applying the corrected configuration does not heal anything. The stuck pod is never automatically replaced. Somebody runs kubectl delete pod app-4, the controller recreates it from the fixed template, and the rollout creeps forward — until the next stuck pod. CI/CD pipelines cannot self-heal through this; platform teams either accept manual intervention as a deployment step or build custom garbage-collection controllers that duplicate StatefulSet logic and risk fighting the real controller.

Wedge shape 2: the mid-rollout edit. Somebody edits the template while a rollout is already in flight — a second fix, a resource tweak, an urgent label. Now the set holds a mix: high ordinals on the new revision, low ordinals on the old one, and the controller halted on a pod that will never go Ready. The replicas disagree about which spec is current, and the state is genuinely hard to reconcile by hand, because every intervention (delete this pod? which template will it come back with?) requires reasoning about revision hashes per ordinal. This is the "inconsistent, hard-to-reconcile state" the original feature request was filed against.

Neither escape hatch operators reach for actually closes these:

Escape hatchWhat it doesWhy the wedge survives
maxUnavailable with OrderedReadyUpdates several pods per stepThe controller still waits for Ready per pod — one stuck pod halts everything, maxUnavailable or not
podManagementPolicy: ParallelUpdates without waiting for ReadyStuck pods stop blocking others, but they are never replaced — the corpses stay until a human deletes them
Custom cleanup controllerDeletes stuck pods externallyDuplicates controller logic, needs maintenance, can conflict with the StatefulSet controller, invisible in StatefulSet status and events

What 1.37 actually ships

The Recreate strategy replaces the wait-and-hope loop with a three-phase algorithm, executed by the StatefulSet controller itself:

  1. Delete. Every pod carrying the old revision hash is deleted — including orphaned pods with ordinals above the replica count. A Progressing status condition (new in the same KEP, for all strategies) tracks the operation.
  2. Wait. The controller pauses until the old-revision pods are fully gone from etcd. No half-deleted state, no recreation racing termination.
  3. Recreate. Pods come back from the current template, with creation order following the existing podManagementPolicy — ascending ordinal with readiness gating under OrderedReady, all at once under Parallel.

The API surface is one field:

yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: tenant-search
spec:
  replicas: 3
  updateStrategy:
    type: Recreate
  template:
    # ... pod spec ...

Enabling it takes the alpha gate on the API server and kube-controller-manager:

console
--feature-gates=StatefulSetRecreateStrategy=true

Three properties of this design are load-bearing for everything below. First, it resolves both wedge shapes with the same motion: a template change — including a fix applied on top of a wedged rollout, including a mid-rollout edit — converges the whole set to the current template instead of negotiating ordinal by ordinal. Second, PersistentVolumeClaims are never deleted; only pods are, so data on volumes survives the operation. Third, flipping updateStrategy.type alone triggers no rollout — consistent with Deployments, where the revision hash derives from the template only. The strategy takes effect on the next template change or on kubectl rollout restart.

The decision table: where Recreate belongs, and where it must not go

Say the downtime sentence plainly, because the entire decision hinges on it: Recreate deletes all pods before creating replacements, so every update is a full outage of that StatefulSet for the duration of the delete-terminate-recreate cycle. There is no rolling anything. That single fact sorts every workload:

WorkloadVerdictWhy
CI/CD and staging environmentsUse itDowntime is acceptable; fast automated recovery beats availability there
Preview environments per pull requestUse itShort-lived by definition; stuck preview rollouts are pure toil
Stateless apps on StatefulSet (stable naming only)Use itNo local state at risk; identity survives via PVC preservation and ordinal naming
Databases on external/network storageEvaluatePod replacement is data-safe, but the full-outage window still applies — fine for dev, scheduled for prod
LeaderWorkerSet-style gang workloadsUse itAll-or-nothing restart matches the pattern; no ordering to preserve
Production tenant databases with local stateDo not use itA full-outage update plus alpha API stability is two risks too many with no managed-database safety net underneath

The KEP is explicit that this is opt-in with no default change, and alpha means the API can still shift before beta. For a production tenant database on owned hardware, the correct posture is unchanged: stay on RollingUpdate, keep the manual runbook, and let the alpha mature elsewhere first.

What a self-hosted PaaS should do this release

Treat v1.37 as the release where the toil around stateful rollouts gets a supported answer for every environment except the one that matters most — and plan accordingly:

  1. Enable the gate on non-production control planes now. Staging, preview, and CI clusters get StatefulSetRecreateStrategy=true and type: Recreate on their StatefulSets. That is where stuck rollouts burn the most operator hours per unit of risk, and alpha feedback from your own fleet is the cheapest way to learn the strategy's sharp edges.
  2. Keep production tenant databases on RollingUpdate with the existing runbook. Document the exclusion as policy, not preference: full-outage updates plus alpha stability do not meet a tenant-facing data plane's bar. Revisit at beta.
  3. Delete the custom cleanup controllers — on the clusters where Recreate lands. If your platform built a stuck-pod deleter, the upstream controller now owns that logic with proper status conditions and events. Retire the duplicate where the strategy is enabled; keep it where it is not.
  4. Standardize kubectl rollout restart as the recovery gesture. Since strategy flips and restarts are the supported triggers, teach one motion instead of per-ordinal pod deletion.

The honest framing for the platform: this release does not make tenant database rollouts safer. It makes every rollout around them cheaper to operate — fewer 2 a.m. pages, CI/CD that heals itself, preview environments that never wedge. The tenant database keeps its boring, manual, rolling updates until the strategy graduates. Boring is the feature there.

The bottom line

StatefulSet's rolling update had exactly one failure mode it could not recover from on its own — the pod that never becomes Ready — and every fleet operated around it with human fingers on kubectl delete pod. Kubernetes 1.37 gives the controller a second motion: stop negotiating with the stuck pod, delete the old revision wholesale, rebuild from the current template. The name changed from flag to strategy along the way; the toil it eliminates did not.

Enable it where downtime is cheap. Keep it away from tenant data until beta. And the next time a rollout wedges at 2 a.m., let the controller do the deleting.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Sources

  • KEP-3541, Add Recreate Update Strategy to StatefulSet — stuck-rollout motivation, RollingUpdate halt algorithm, Recreate three-phase algorithm, user stories, risks
  • Kubernetes docs, StatefulSetsRecreate strategy alpha since v1.37, StatefulSetRecreateStrategy gate, per-strategy behavior
  • Cloudsmith, Kubernetes 1.37: What You Need to Know — 1.37 tracker listing, KEP-3541 net-new-to-alpha status
  • Kubernetes enhancement issue #3541 — original EnforcedRollingUpdate proposal title and KEP link
  • Kubernetes issue #113671 — toleration-change restart gap, enforcedRollingUpdate as prospective automation
  • KubeCon NA 2025 SIG Apps deck — "How resolve stuck pods in a rollout?" naming KEP-3541 alongside Deployment pod-replacement policy work

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex