Kubernetes In-Place Pod Resize: CPU & Memory No Restart

Photo by Bernd Dittrich on Unsplash
It is the ability to change a running container's CPU and memory requests and limits through the pod's resize subresource, usually without restarting the pod. It makes spec.containers resources mutable for CPU and memory, so requests can track real usage instead of being frozen at creation.
It was introduced as alpha in v1.27, graduated to beta and became enabled by default in v1.33 (May 2025), and reached stable (GA) in Kubernetes v1.35 on 19 December 2025, behind the InPlacePodVerticalScaling feature gate.
Target the pod's resize subresource, for example with kubectl patch --subresource resize, sending only the new CPU or memory requests and limits. The kubelet reconfigures the container's cgroup limits in place when the resizePolicy for that resource is NotRequired, which is the default.
resizePolicy is set per resource. NotRequired (the default) applies the new value to the live container with no restart. RestartContainer restarts just that container to pick up the change, which is needed for apps that only read a resource at startup, such as a JVM heap sized from its memory limit.
The old Recreate mode evicts and reschedules the pod to apply new requests, which is a restart. InPlaceOrRecreate first attempts a disruption-free in-place resize and only falls back to eviction if that fails or the node cannot fit it. It graduated to beta alongside the v1.35 GA of in-place resize.

Photo by Bernd Dittrich on Unsplash
Key Takeaway
Kubernetes in-place pod resize lets you change a running container's CPU and memory requests and limits through the pod's resize subresource, usually without a restart. Introduced as alpha in v1.27, it reached beta in v1.33 and graduated to stable in v1.35, and the Vertical Pod Autoscaler's InPlaceOrRecreate mode builds on it.
For most of Kubernetes' history, a pod's CPU and memory requests were effectively frozen at creation. The spec.containers resources field was immutable, so the only way to give a container more memory or claw back unused CPU was to replace the pod entirely. For a stateless web app that is a shrug. For a stateful service, a long-running batch job, or anything holding an in-memory cache, a restart is real downtime and lost work.
That immutability is what made vertical autoscaling so blunt. The Vertical Pod Autoscaler could recommend better numbers, but to apply them its Recreate mode had to evict the pod and let the scheduler recreate it with the new requests. You paid for right-sizing with a disruption every single time. In-place pod resize is the change that finally removes that tax.
The Vertical Pod Autoscaler has four classic update modes: Off (recommend only), Initial (set requests at creation), and Recreate or Auto (actively update running pods). The catch is how Recreate applies an update — it evicts the pod when the current requests differ significantly from the new recommendation, and a fresh pod comes back with the corrected numbers. Eviction respects PodDisruptionBudgets, but it is still a restart.
To stay safe against that, teams overprovision. If you cannot resize without a restart, you request the peak you might ever need and leave it there, so nodes carry a permanent buffer of reserved-but-idle CPU and memory. Multiply that headroom across every workload and you are paying for capacity the scheduler has fenced off but nothing is using. In-place resize is the mechanism that finally lets requests track reality.
As of the v1.35 GA, spec.containers resources is mutable for CPU and memory and represents the desired state; status.containerStatuses resources reports what the container has actually been allocated. You declare per-resource restart behaviour with resizePolicy — each entry pairs a resourceName (cpu or memory) with a restartPolicy of either NotRequired, the default, which applies the change to the live container, or RestartContainer, which restarts just that container to pick up the new value.
apiVersion: v1
kind: Pod
metadata:
name: reports-worker
spec:
containers:
- name: worker
image: registry.example.com/reports-worker:2.1.0
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
resources:
requests:
cpu: 250m
memory: 256Mi
limits:
cpu: "1"
memory: 512MiNotRequired is the whole point: the kubelet reconfigures the running container's cgroup limits in place, with no new pod and no rescheduling. RestartContainer exists for runtimes or apps that can only read a resource at startup — a JVM heap sized from a memory limit is the classic case. The policy is per resource, so you can resize CPU live while forcing a restart on a memory change.
The kubectl --subresource resize flag needs a client of at least v1.32. On older kubectl you can still change resources through the API, but the convenient patch and edit shortcuts against the resize subresource will not be available — upgrade the client, not just the cluster.
You do not edit the pod normally — you target its resize subresource. kubectl patch --subresource resize sends only the new requests or limits, and the kubelet reconciles the difference. Two status conditions tell you how it is going: PodResizePending means the kubelet cannot grant the change yet (reason Deferred when it is temporary, Infeasible when the node simply cannot fit it), and PodResizeInProgress means the change was accepted and is being applied.
# Bump CPU and memory requests on a running pod, no restart
kubectl patch pod reports-worker --subresource resize --patch \
'{"spec":{"containers":[{"name":"worker","resources":{"requests":{"cpu":"500m","memory":"384Mi"}}}]}}'
# Watch the two status conditions the kubelet reports
kubectl get pod reports-worker -o jsonpath='{.status.conditions[?(@.type=="PodResizeInProgress")]}'
# spec.containers[*].resources is the DESIRED state (mutable)
# status.containerStatuses[*].resources is the ACTUAL allocated stateOne rule caught me early. Through the beta, decreasing a memory limit on a running container was rejected outright. The v1.35 GA lifted that restriction: memory limit decreases are now allowed, and the kubelet does a best-effort check — it applies the shrink only if current usage is already below the new limit, to avoid an immediate OOM kill. Best-effort means not guaranteed, so shrink memory limits with care.
In-place resize changes a running pod, but the workload controller does not know. If a Deployment or its VPA later recreates that pod from the original template, your resized values are gone and it comes back at the template's requests. Push the corrected numbers into your source of truth — the template, or a VPA object — or the next reschedule quietly reverts them.
The autoscaler team built two new VPA modes on top of the resize subresource. Both attempt a disruption-free in-place update first; they differ in the fallback:
The two approaches reach the same goal — a pod running with the right requests — but the cost to get there is completely different:
| Aspect | VPA Recreate (old way) | In-place resize |
|---|---|---|
| Disruption | Pod evicted and rescheduled | Running container reconfigured, usually no restart |
| In-memory state | Lost on eviction | Preserved when the policy is NotRequired |
| How it applies | Delete pod, scheduler recreates | Mutate resources via the resize subresource |
| Overprovisioning | Encouraged — restarts are costly | Reduced — requests can track real usage |
| Maturity | Stable for years | GA in Kubernetes v1.35 |
The practical upshot is that right-sizing stops being a scheduled, disruptive event and becomes a routine adjustment. A batch job that under-requested memory can grow mid-run instead of being OOM-killed and restarted; an over-provisioned service can hand CPU back to the node without anyone noticing.
If you run Kubernetes v1.35 or later, in-place resize is on by default and worth using deliberately — start by setting sensible resizePolicy entries on stateful and batch workloads, and verify RestartContainer where an app reads its limits only at boot. For automated right-sizing, pilot VPA InPlaceOrRecreate on a non-critical namespace first, watch the PodResizePending and PodResizeInProgress conditions, and confirm your templates or VPA objects hold the corrected requests so nothing reverts on the next reschedule.
Sources