kubectl rollout restart on a StatefulSet or DaemonSet
kubectl rollout restart writes the current time into the pod
template's kubectl. annotation. The
template changed, so the controller replaces the pods under its update strategy, as it would
after a new image. A StatefulSet replaces one pod at a time, from the highest ordinal down, and
waits for each new pod to be Running and Ready. It replaces only some pods, or none, when its
updateStrategy is OnDelete, when
rollingUpdate. is above 0, or when a pod is not Ready. On GKE 1.36 a
not-Ready pod stopped our restart before any pod was replaced, and a new pod that never got
Ready left it at one pod of three. A DaemonSet replaces one node's pod at a time
(maxUnavailable: 1, maxSurge: 0 by default). A PodDisruptionBudget does
not hold back a restart; it limits evictions, which is why kubectl drain hangs on
Cannot evict pod as it would violate the pod's disruption budget.
By Ostgate · Updated
The test
We ran this on 11 November 2026 on a GKE Autopilot cluster, version 1.36.4-gke.2377000, with
kubectl 1.35. The StatefulSet web has three replicas of
busybox:1.37, each requesting 50m CPU and 64Mi of memory. Its readiness probe
fails while the pod carries the label seo-notready, so a pod can be made not
Ready with kubectl label. The container exits on SIGTERM, so a pod stops in about a
second. The DaemonSet agent runs the same container on every node; the cluster had
13 to 15 nodes at the time.
What kubectl rollout restart changes
kubectl -n NAMESPACE rollout restart statefulset/web
kubectl -n NAMESPACE get statefulset web -o jsonpath='{.spec.template.metadata.annotations}'
statefulset.apps/web restarted
{"kubectl.kubernetes.io/restartedAt":"2026-11-11T14:41:03+01:00"}
kubectl sets the annotation to time. in RFC 3339, so it carries the
local time of the machine you ran it from. That is the whole command: kubectl deletes no pod
itself. The same code refuses a paused Deployment with can't restart paused deployment
(run rollout resume first). The kubectl reference says only “Resource rollout will be
restarted”
(kubectl
rollout restart), so what happens next depends on the controller's update strategy.
Read the strategy first:
kubectl -n NAMESPACE get statefulset web -o jsonpath='{.spec.updateStrategy}{"\n"}{.spec.podManagementPolicy}{"\n"}'
{"rollingUpdate":{"partition":0},"type":"RollingUpdate"}
OrderedReady
RollingUpdate: every pod, highest ordinal first
With the defaults above, the restart replaced all three pods in 10 seconds. The StatefulSet's events:
13:41:03Z SuccessfulDelete Delete Pod web-2 in StatefulSet web successful 13:41:06Z SuccessfulCreate Create Pod web-2 in StatefulSet web successful 13:41:07Z SuccessfulDelete Delete Pod web-1 in StatefulSet web successful 13:41:09Z SuccessfulCreate Create Pod web-1 in StatefulSet web successful 13:41:10Z SuccessfulDelete Delete Pod web-0 in StatefulSet web successful 13:41:12Z SuccessfulCreate Create Pod web-0 in StatefulSet web successful
kubectl -n NAMESPACE rollout status statefulset/web
Waiting for partitioned roll out to finish: 0 out of 3 new pods have been updated... Waiting for 1 pods to be ready... Waiting for partitioned roll out to finish: 1 out of 3 new pods have been updated... Waiting for 1 pods to be ready... Waiting for partitioned roll out to finish: 2 out of 3 new pods have been updated... Waiting for 1 pods to be ready... partitioned roll out complete: 3 new pods have been updated...
kubectl says “partitioned” for every StatefulSet, because the API fills in
partition: 0. The order is the documented one: the controller “will delete and
recreate each Pod in the StatefulSet. It will proceed in the same order as Pod termination
(from the largest ordinal to the smallest), updating each Pod one at a time”, and it “waits
until an updated Pod is Running and Ready prior to updating its predecessor”
(StatefulSets).
Each old pod is deleted before its replacement is created, so a StatefulSet with one replica
has no running pod while the new one starts.
Only one pod restarted: partition
kubectl -n NAMESPACE patch statefulset web --type merge \
-p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
kubectl -n NAMESPACE rollout restart statefulset/web
kubectl -n NAMESPACE rollout status statefulset/web
Waiting for partitioned roll out to finish: 0 out of 1 new pods have been updated... Waiting for 1 pods to be ready... partitioned roll out complete: 1 new pods have been updated...
NAME CREATED REVISION web-0 2026-11-11T13:41:12Z web-b5477fcb6 web-1 2026-11-11T13:41:09Z web-b5477fcb6 web-2 2026-11-11T13:41:24Z web-5cbb9d779f
Only web-2 got the new revision, and rollout status calls that
complete. When we deleted web-0, it came back on the old revision: “All Pods with an
ordinal that is less than the partition will not be updated, and, even if they are deleted,
they will be recreated at the previous version”
(StatefulSets).
A partition left behind after a canary is a common reason a restart touches one pod. Set it
back to 0 and the rest follow; ours finished 6 seconds later:
kubectl -n NAMESPACE patch statefulset web --type merge \
-p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
No pod restarted: OnDelete
With updateStrategy: {type: OnDelete} the restart printed
statefulset.apps/web restarted and nothing else happened. 45 seconds later all
three pods were still on the old revision, and rollout status refused with exit
code 1:
error: rollout status is only available for RollingUpdate strategy type
That is the documented behaviour: the controller “will not automatically update the Pods in a StatefulSet. Users must manually delete Pods to cause the controller to create new Pods” (StatefulSets). Delete them one at a time, waiting for each to be Ready:
kubectl -n NAMESPACE delete pod web-1
Our web-1 came back 2 seconds later on the new revision; web-0 and
web-2 stayed old until we deleted them or switched the strategy back to
RollingUpdate.
A pod that isn't Ready stalls the rollout
An old pod not Ready: nothing restarts
We made web-0 not Ready, then restarted. web-2 and
web-1 were Ready, yet the controller replaced no pod at all:
Waiting for 1 pods to be ready... error: timed out waiting for the condition
After 90 seconds all three pods still had their old creation times and revision. Under the
default OrderedReady policy, “Before a scaling operation is applied to a Pod, all
of its predecessors must be Running and Ready”
(StatefulSets),
and our update waited the same way. When web-0 turned Ready again, the waiting
rollout ran by itself and replaced all three pods within 8 seconds. Find the pod it waits for:
kubectl -n NAMESPACE get pods -l app=web -o wide kubectl -n NAMESPACE describe pod web-0
A new pod never gets Ready: one pod restarts
This is the usual “only restarted one pod” report. We changed the template so that new pods fail
their readiness probe. web-2 was replaced and stayed READY false, with
Readiness probe failed events; web-1 and web-0 were never
touched. A rollout restart on top made no difference.
NAME CREATED REVISION READY web-0 2026-11-11T13:46:01Z web-77c59d8cbc true web-1 2026-11-11T13:45:59Z web-77c59d8cbc true web-2 2026-11-11T13:46:13Z web-587994888b false
Fixing the template is not enough. We reverted it, and 60 seconds later web-2 was
still the broken pod. The docs describe this as a broken state under OrderedReady:
“StatefulSet will stop the rollout and wait”, and “After reverting the template, you must also
delete any Pods that StatefulSet had already attempted to run with the bad configuration”
(Forced
rollback). Deleting it finished the rollout in 8 seconds:
kubectl -n NAMESPACE delete pod web-2
podManagementPolicy Parallel and maxUnavailable
Faster StatefulSet rollouts need two settings. podManagementPolicy: Parallel
can only be set when the StatefulSet is created, and with it “when
.spec. is greater than 1,
the StatefulSet controller terminates and creates up to maxUnavailable Pods
simultaneously”. maxUnavailable is “Beta since Kubernetes v1.37; enabled by
default”
(StatefulSets).
On our GKE 1.36.4 cluster the field didn't stick: kubectl patch answered
statefulset.apps/web patched, and reading the strategy back showed no
maxUnavailable. We did not test Parallel.
kubectl rollout restart daemonset
kubectl -n NAMESPACE rollout restart daemonset/agent kubectl -n NAMESPACE rollout status daemonset/agent
Waiting for daemon set "agent" rollout to finish: 0 out of 14 new pods have been updated... Waiting for daemon set "agent" rollout to finish: 1 out of 14 new pods have been updated... … Waiting for daemon set "agent" rollout to finish: 13 of 14 updated pods are available... daemon set "agent" successfully rolled out
Autopilot accepted the DaemonSet. Its strategy read back as
{"rollingUpdate":,
and the restart replaced 14 pods one node at a time in 30 seconds. Raising
maxUnavailable replaces more nodes' pods at once. With OnDelete, “new
DaemonSet pods will only be created when you manually delete old DaemonSet pods”
(Perform a rolling
update on a DaemonSet); we did not run that case.
maxSurge starts the new pod before the old one stops, and “can not be 0 if
MaxUnavailable is 0”. The API reference warns that “the resources consumed by the daemonset
on any given node can double”
(DaemonSet
API). That stopped our rollout. With maxUnavailable: 0 and
maxSurge: 1 it reached 6 out of 13 new pods have been updated and
stayed there: the new pod for one full node was Pending with
0/15 nodes are available: 1 Insufficient memory, 14 node(s) didn't satisfy plugin(s)
[NodeAffinity], because a DaemonSet pod is pinned to its node and the old pod still held
its memory. Setting maxUnavailable: 1, maxSurge: 0 finished the rollout in 18
seconds.
PodDisruptionBudgets and drains
A PodDisruptionBudget limits evictions, and a rollout restart evicts nothing: the controller
deletes and creates pods itself. Pods replaced by a rolling update “do count against the
disruption budget, but workload resources (such as Deployment and StatefulSet) are not limited
by PDBs when doing rolling upgrades”
(Disruptions).
kubectl drain, GKE node upgrades and anything else that calls the Eviction API
wait for the budget.
| Operation | Waits for the PDB? | Source |
|---|---|---|
kubectl rollout , a new image, any rolling update |
No | Our runs below; Disruptions |
kubectl delete pod, deleting a Deployment |
No: “deleting deployments or pods bypasses Pod Disruption Budgets” | Disruptions |
| An Eviction through the API | Yes, refused with HTTP 429 | Our run below |
kubectl drain |
Yes, retries every 5 seconds with no time limit by default | kubectl source; Safely drain a node |
| GKE node upgrade (surge, the only kind on Autopilot) | Yes, for up to one hour, then evicts anyway | GKE docs |
A restart goes through a budget that allows 0
We gave a three-replica Deployment a budget that allows no disruption at all, the case the docs describe as “requiring zero voluntary evictions” (Specifying a Disruption Budget):
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: web
spec:
minAvailable: 3
selector:
matchLabels:
app: web
kubectl -n NAMESPACE get pdb web kubectl -n NAMESPACE rollout restart deployment/web kubectl -n NAMESPACE rollout status deployment/web
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE web 3 N/A 0 11s deployment.apps/web restarted Waiting for deployment "web" rollout to finish: 1 out of 3 new replicas have been updated... Waiting for deployment "web" rollout to finish: 2 out of 3 new replicas have been updated... Waiting for deployment "web" rollout to finish: 1 old replicas are pending termination... deployment "web" successfully rolled out
All three pods were replaced in 16 seconds while the budget stayed at ALLOWED
DISRUPTIONS 0. The events show each new pod created before an old one was deleted, the
Deployment's default surge. A StatefulSet has no surge and deletes first, and it went below the
budget without waiting: in our first run it replaced all three pods in 7 seconds under the
same minAvailable: 3.
An eviction is refused: Cannot evict pod
An eviction is the request kubectl drain sends for each pod on the node. We sent
one for a single pod, which shows the same refusal without touching a node. Save the request
as eviction.json:
{"apiVersion":"policy/v1","kind":"Eviction","metadata":{"name":"POD","namespace":"NAMESPACE"}}
kubectl create --raw /api/v1/namespaces/NAMESPACE/pods/POD/eviction -f eviction.json
Error from server (TooManyRequests): Cannot evict pod as it would violate the pod's disruption budget.
The response was HTTP 429, and its cause names the budget: The disruption budget web
needs 3 healthy pods and has 3 currently. The pod kept running. The docs list 429 as
“not currently allowed because of the configured PodDisruptionBudget” and 500 as a
misconfiguration, “like if multiple PodDisruptionBudgets reference the same Pod”
(API-initiated
eviction).
kubectl drain treats a 429 as temporary. Its source prints the server's message in
this form and tries again 5 seconds later:
error when evicting pods/"POD" -n "NAMESPACE" (will retry after 5s): Cannot evict pod as it would violate the pod's disruption budget.
Its --timeout is 0 by default, which means no limit, so a drain against a budget
that allows 0 prints that line every 5 seconds until someone stops it. The docs put it the
same way: “If you try to drain a Node where an unevictable Pod is running, the drain never
completes”
(Specifying a
Disruption Budget). A budget below the replica count can also block a drain when one of
its pods is not Ready, because “Any drains that would cause the number of healthy replicas to
fall below the specified budget are blocked”
(Safely drain a
node). Find the budgets that allow nothing:
kubectl get pdb -A
The fix: let one pod go
Replace minAvailable: 3 with maxUnavailable: 1 in the manifest. A
budget holds only one of the two fields, so replace the whole object rather than adding the
second field. The docs suggest maxUnavailable 1 for replicated stateful apps
because it “works with varying scale of application”; a lower minAvailable, such
as 2 of 3, allows one eviction as well.
kubectl -n NAMESPACE replace -f pdb.yaml kubectl -n NAMESPACE get pdb web
NAME MIN AVAILABLE MAX UNAVAILABLE ALLOWED DISRUPTIONS AGE web N/A 1 1 56s
The same eviction then answered 201 Created with
"status":"Success", and the Deployment started a replacement pod. A second eviction
sent in the same second was refused with needs 2 healthy pods and has 2 currently,
because the replacement was not Ready yet. Ten seconds later it was Ready, the budget showed
ALLOWED DISRUPTIONS 1 again, and the second eviction went through. A drain's
retries get the same answers, so pods under this budget leave one at a time.
If a pod in the budget is stuck not Ready, the docs recommend
unhealthyPodEvictionPolicy: AlwaysAllow: running pods that are not yet healthy
“can be evicted regardless of whether the criteria in a PDB is met”
(Unhealthy
Pod Eviction Policy). We did not test that setting.
GKE node upgrades and Autopilot
For surge upgrades GKE will “Drain the existing node, respecting PodDisruptionBudget and GracefulTerminationPeriod settings for up to one hour”, and “After one hour, any remaining Pods are forcefully evicted so that the upgrade can proceed”. GKE uses surge upgrades on Autopilot clusters. A blue-green upgrade, an option on Standard clusters, ends by deleting the old pool: “Unlike eviction, deletion doesn't respect PDBs and forcibly deletes the Pods” (Node pool upgrade strategies). A budget that allows 0 holds each node's upgrade for up to an hour, and then its pods are evicted anyway.
On Autopilot, the annotation
cluster-
on a pod goes further: such pods “are protected from eviction caused by node auto-upgrades or
scale-down events for up to seven days”
(Autopilot
overview). We did not run a node upgrade or a drain: Autopilot nodes are Google's to manage.
How Ostgate does it
In a cluster's tab in Ostgate, Restart… on a Deployment, StatefulSet or DaemonSet
replaces its pods under its rollout strategy, as kubectl rollout restart does. The
confirmation names the account, project, cluster and namespace, counts the pods that go down at
once, and says when an OnDelete StatefulSet would restart nothing. Ostgate asks the
cluster first whether your account may restart the workload; when it may not,
Restart… is disabled and says which permission is missing
(Restart and delete). Delete Pod… deletes one pod, and
its controller creates the replacement.
Symptoms and causes
| You see | Cause | Fix |
|---|---|---|
Only the highest-ordinal pod is new; rollout says complete |
rollingUpdate. above 0 |
Set the partition to 0 |
restarted, but no pod changes; rollout |
updateStrategy: |
Delete the pods one at a time, or switch to RollingUpdate |
No pod changes; Waiting |
An existing pod is not Ready | Fix or delete that pod |
| One new pod stays not Ready, the others are old | The new template never becomes Ready | Fix the template, then delete the broken pod |
maxUnavailable gone from a StatefulSet after patched |
Dropped on our GKE 1.36 cluster; beta from Kubernetes 1.37 | Delete pods yourself, or check again on 1.37 |
DaemonSet rollout stops; a new pod Pending with Insufficient |
maxSurge needs room for two pods on a full node |
maxUnavailable: , maxSurge: |
can't |
The Deployment is paused | kubectl first |
kubectl drain hangs; Cannot |
A PDB with ALLOWED |
maxUnavailable: or a lower minAvailable; fix pods that are not Ready |
| A GKE node upgrade waits on one node for up to an hour | A PDB allows no eviction from that node | The same budget fix; after one hour GKE evicts anyway |
Questions
How do I restart a rollout?
Run kubectl rollout restart deployment/NAME, statefulset/NAME or daemonset/NAME, then kubectl rollout status on the same object. The command sets the pod template annotation kubectl. to the current time, and the controller replaces the pods under its update strategy. A paused Deployment needs kubectl rollout resume first.
How do I force a pod to restart?
Delete it: kubectl delete pod NAME. A Deployment, StatefulSet or DaemonSet creates a replacement; a StatefulSet pod comes back with the same name. Below a partition it comes back on the old revision, and under OnDelete deleting is the only way to move a pod to the new template. A pod without a controller is not recreated.
Why does kubectl rollout restart statefulset only restart one pod?
Either rollingUpdate. is set, so only ordinals at or above it are replaced, or the first new pod never became Ready, so the ordered rollout waits. In our test on GKE 1.36 a not-Ready web-0 stopped the restart before any pod was replaced, and a new web-2 that failed its readiness probe left web-1 and web-0 untouched until we deleted it. With OnDelete no pod is replaced at all.
Does a PodDisruptionBudget stop kubectl rollout restart?
No. With minAvailable: 3 on three pods and no disruptions allowed, our restart still replaced all three, one at a time. Rolling updates count against the budget but are not limited by it; the budget limits evictions, such as those from kubectl drain.
Why does kubectl drain hang with Cannot evict pod as it would violate the pod's disruption budget?
A PodDisruptionBudget on one of the node's pods allows 0 disruptions: minAvailable equal to the replica count, maxUnavailable: 0, or a budget whose pods are not all Ready. Each eviction gets HTTP 429, and kubectl drain retries every 5 seconds with no time limit unless you pass --timeout. Run kubectl get pdb -A and look for ALLOWED DISRUPTIONS 0, then set maxUnavailable: 1 or a lower minAvailable, or fix the pod that is not Ready. In our test the refused eviction went through as soon as the budget allowed 1.
Ostgate runs on Apple Silicon Macs with macOS 15 or later, with a 7-day trial and no sign-up. Setup is in the GKE docs, and GKE on a Mac lists what the GKE area does.