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 old problem: VPA Recreate evicts your pods
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.
How in-place resize works: the resize subresource
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.
Triggering a resize with kubectl
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.
Where VPA InPlaceOrRecreate comes in
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:
- InPlaceOrRecreate tries the resize in place, and if it fails or the node cannot fit it, falls back to evicting and recreating the pod — the pragmatic default when you want right-sizing to always eventually happen.
- InPlace applies updates the same way but never evicts; if the resize cannot be granted, the pod simply keeps its current resources until it can.
- Either mode fires an update on a quick OOM, when usage drifts outside the recommended range, or when the recommendation changes significantly — the same triggers VPA already used, now without a guaranteed restart.
- InPlaceOrRecreate graduated to beta alongside the v1.35 GA of the underlying resize feature, so treat it as promising but still stabilising for production rollouts.
Old VPA Recreate versus in-place resize
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.
Should you turn it on?
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
- Kubernetes v1.33: In-Place Pod Resize Graduated to Beta (kubernetes.io blog)
- Kubernetes v1.35: In-Place Pod Resize Graduates to Stable (kubernetes.io blog)
- Resize CPU and Memory Resources assigned to Containers (kubernetes.io docs)
- Vertical Pod Autoscaler features — in-place updates (kubernetes/autoscaler docs)

