Kubernetes in-place pod resize hits GA in v1.35: rightsize pods without restarts
Summary. In-place pod resize graduated to stable in Kubernetes v1.35 on 19 December 2025, more than 6 years after the idea was first filed as KEP-1287 and 2 releases after its v1.33 beta. You can now change spec.containers[*].resources on a running pod through the resize subresource, and for CPU the container usually does not restart. The timing is useful. Cast AI's 2026 State of Kubernetes Optimization Report, published 21 April 2026 from measurements across tens of thousands of production clusters on AWS, GCP and Azure, put average CPU utilisation at 8% and memory at 20%, with CPU over-provisioning rising from 40% to 69% year over year. On a 50-node m7i.xlarge cluster billed at the us-east-1 on-demand rate of $0.2016 per hour, the compute line alone is about $7,358 a month. In v1.36, released 22 April 2026, pod-level in-place vertical scaling reached beta. The catch: memory changes still restart most containers, Windows nodes are excluded, and pods pinned by the static CPU manager cannot resize in place at all.
What actually changed in v1.35
Before this, resources.requests and resources.limits were immutable. Changing them meant deleting the pod and letting a controller build a new one. For a stateful service or a long-running batch job, that is a real outage, not a config tweak.
The v1.35 release makes CPU and memory requests and limits mutable on a running pod. Natasha Sarkar of Google, who wrote the release announcement, described the model in three parts:
spec.containers[*].resources is the desired state, and for CPU and memory it is now mutable. status.containerStatuses[*].resources is the actual state, meaning what the running container currently has. You request a change by patching the pod's resize subresource, and the kubelet then decides whether it can apply it.
The feature took a long path: alpha in v1.27 (May 2023), beta in v1.33 (May 2025), stable in v1.35 (December 2025). Per the Kubernetes release history, v1.35 reached patch 1.35.6 on 9 June 2026 and goes end of life on 28 February 2027, while v1.36 goes end of life on 28 June 2027.
Four things changed between the v1.33 beta and the v1.35 stable release:
- Memory limit decreases are allowed, having been prohibited before. The kubelet now permits a decrease only if current memory usage is below the new limit. This is best-effort, not a guarantee, and it is still exposed to a race where usage spikes right after the check.
- Deferred resizes are prioritised. When a node cannot fit every pending resize, retries are ordered by PriorityClass, then QoS class (Guaranteed before Burstable), then by how long the request has been deferred.
- Pod-level resources support landed as alpha, behind its own feature gate.
- Observability improved, with new kubelet metrics and pod events specific to resize.
The waste this is aimed at
The case for rightsizing is not subtle. Cast AI has now run its utilisation study three years running. The 2026 edition reports CPU utilisation of 8%, down from 10% the year before, and memory down from 23% to 20%. These are direct measurements from production clusters before any optimisation, not survey estimates or projections.
The over-provisioning gap is widening rather than closing. CPU over-provisioning jumped from 40% to 69% year over year; memory sits at 79%. Organisations are paying for capacity their workloads do not even request, let alone use.
Laurent Gil, co-founder and president of Cast AI, framed the economics bluntly in the report's launch announcement on 21 April 2026, a point that lands alongside the EC2 Capacity Blocks GPU price rise: "A GPU sitting idle costs dollars per hour. A CPU sitting idle costs cents. And 95% of GPU capacity is doing nothing."
The mechanism behind the waste is mundane. Teams pad requests to avoid throttling and OOM kills, that padding is invisible to whoever owns the platform bill, and nothing forces a revisit after deployment. Helm charts ship conservative defaults. Cluster autoscalers read inflated requests as genuine demand and provision nodes to match. The gap becomes structural.
The counterintuitive finding is worth pausing on. Cast AI reports one cluster that averaged 40 to 50 OOM kills per measurement interval under generous padding; after automated rightsizing was applied, which also cut provisioned CPUs by roughly half, OOM kills fell to near zero. More headroom did not mean fewer crashes. The rightsizing agent raised memory limits for the workloads actually under pressure, which is exactly what a static pad set six months ago never does.
The real cost of over-provisioning is not the wasted core. It is that nobody can tell which workloads genuinely need headroom.
What it costs you
Concrete arithmetic, using a published rate. An m7i.xlarge carries 4 vCPU and 16 GiB and lists at $0.2016 per hour on-demand in us-east-1, which is $147.17 per month per node.
| Cluster size (m7i.xlarge) | vCPU provisioned | On-demand compute per month | If provisioned CPU halves |
|---|---|---|---|
| 10 nodes | 40 | $1,471.68 | $735.84 |
| 25 nodes | 100 | $3,679.20 | $1,839.60 |
| 50 nodes | 200 | $7,358.40 | $3,679.20 |
| 100 nodes | 400 | $14,716.80 | $7,358.40 |
| 250 nodes | 1,000 | $36,792.00 | $18,396.00 |
The right-hand column is not a promise. It is the arithmetic if you achieve the roughly-half reduction Cast AI observed in the single cluster it profiled. Your number depends on how much padding you started with. The point of the table is the order of magnitude: on a mid-sized cluster this is a five-figure annual line item, and it recurs every month you leave it alone.
Two caveats a senior team should apply before quoting these figures internally. First, on-demand list price is the ceiling; if you already run Savings Plans, reservations or Spot, your effective rate is lower and so is the saving. Second, reclaiming requests only saves money once the cluster autoscaler actually removes nodes, which needs the workloads to bin-pack onto fewer machines. Rightsizing requests without consolidating nodes changes the graph and not the invoice.
How a resize actually works
Set a resize policy per resource on the container. This is the field that decides whether you get a restart:
apiVersion: v1
kind: Pod
metadata:
name: resize-demo
namespace: qos-example
spec:
containers:
- name: pause
image: registry.k8s.io/pause:3.8
resizePolicy:
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
Then patch the resize subresource:
kubectl patch pod resize-demo -n qos-example --subresource resize --patch \
'{"spec":{"containers":[{"name":"pause", "resources":{"requests":{"cpu":"800m"}, "limits":{"cpu":"800m"}}}]}}'
With restartPolicy: NotRequired on CPU, status.containerStatuses[0].resources moves to cpu: 800m and restartCount stays at 0. Patch memory instead, with RestartContainer set, and restartCount increments to 1.
The --subresource resize flag needs kubectl v1.32.0 or later. Older clients report an invalid subresource error, which is a common first stumble.
The resize policy table
| Setting | Behaviour | Use it for | Restart? |
|---|---|---|---|
NotRequired (default) |
Applies the change to the running container | CPU on almost everything | No |
RestartContainer |
Restarts the container to apply values | Memory on JVM, CPython, most runtimes | Yes |
| Unset | Defaults to NotRequired
|
Nothing; be explicit | No |
NotRequired + memory decrease |
Best-effort OOM check, skipped if usage exceeds new limit | Cautious memory reclaim | No |
Pod restartPolicy: Never
|
Forces NotRequired on every resource |
Run-once pods | Not permitted |
The memory row is where teams get caught. Java and Python runtimes do not resize their heap without a restart, and the Kubernetes maintainers say so directly: there is an open conversation with the Java developers about it. If your workload is a JVM service, plan for RestartContainer on memory and treat CPU as the part you tune live.
Reading resize status
The kubelet reports state through pod conditions rather than failing the patch:
-
PodResizePendingwithreason: Infeasiblemeans the node can never satisfy it, for example a request larger than the node. -
PodResizePendingwithreason: Deferredmeans not now, maybe later; the kubelet retries. -
PodResizeInProgressmeans accepted and being applied. Errors during actuation surface inmessagewithreason: Error.
Ask for 1000 full cores on a small node and you get Infeasible, with a message naming the requested and available capacity, while status.containerStatuses[0].resources keeps the old values and restartCount does not move. The desired spec changes; the actual allocation does not. That split is the thing to monitor, because a patch that "succeeded" against the API server can sit unapplied on the node indefinitely.
Use status.observedGeneration, stable since v1.35, to tell which metadata.generation the kubelet has actually processed. Without it you cannot distinguish a resize that is still in flight from one the kubelet never saw.
What you still cannot do
The limitations list is the part worth reading twice, because it decides whether this feature applies to your fleet at all. As of Kubernetes 1.36:
| Limitation | Detail | Who it blocks |
|---|---|---|
| Resource types | Only CPU and memory can be resized | Anyone hoping to resize GPUs or ephemeral storage |
| Operating system | Windows pods do not support in-place resize | Mixed Windows fleets |
| Node policies | Pods under static CPU or Memory manager policies cannot resize in place | Latency-critical, pinned workloads |
| QoS class | Original QoS class is fixed at creation and a resize cannot change it | Burstable pods that would become Guaranteed |
| Swap | Pods using swap cannot resize memory requests unless memory policy is RestartContainer
|
Nodes with swap enabled |
| Container types | Non-restartable init containers and ephemeral containers cannot be resized; sidecars can | Init-heavy pods |
| Resource removal | Requests and limits cannot be removed once set, only changed | Anyone trying to unset a limit |
The QoS rule catches people. A Guaranteed pod must keep requests equal to limits after the resize. A Burstable pod cannot have requests and limits become equal for both CPU and memory at once, because that would promote it to Guaranteed. A BestEffort pod cannot have requests or limits added at all. The class you chose at creation is the class you tune within.
Pod-level resize: what v1.36 added
Pod-level resources reached beta in v1.34, in-place container resize went GA in v1.35, and v1.36 joined them: in-place vertical scaling of the aggregate pod budget (.spec.resources) is beta and on by default via the InPlacePodLevelResourcesVerticalScaling gate.
This matters for pods with sidecars, where containers share a collective pool instead of each holding an individual limit. You can now widen that pool on a running pod:
kubectl patch pod shared-pool-app --subresource resize --patch \
'{"spec":{"resources":{"limits":{"cpu":"4"}}}}'
Two details are easy to miss.
There is no pod-level resize policy. The kubelet always defers to each container's resizePolicy to decide whether that container restarts. So a pod-level CPU patch can restart a container that never declared its own CPU limit, because that container implicitly inherited the pod limit as its ceiling and its policy said RestartContainer. The Kubernetes documentation walks through exactly this case: patch a pod limit from 200m to 300m and a container with RestartContainer on CPU restarts, despite the patch targeting the pod.
The kubelet also sequences cgroup writes to avoid overshoot. Increasing, it expands the pod cgroup first to make room, then the container cgroups. Decreasing, it throttles the containers first, then shrinks the pod cgroup.
Pod-level resize also adds validation of its own: pod-level requests must be at least the sum of container requests, while individual container limits must not exceed the pod limit, though the sum of container limits may exceed it.
Requirements are stricter than container-level resize: cgroup v2 only, a runtime supporting the UpdateContainerResources CRI call such as containerd v2.0+ or CRI-O, Linux nodes only, and four gates enabled (PodLevelResources, InPlacePodVerticalScaling, InPlacePodLevelResourcesVerticalScaling, NodeDeclaredFeatures).
Wiring it to the Vertical Pod Autoscaler
Patching pods by hand is a demo, not an operating model. The value arrives when an autoscaler drives the resize.
The Kubernetes v1.35 announcement described VPA's InPlaceOrRecreate mode as newly beta. That note has aged: the VPA project's own feature documentation now lists InPlaceOrRecreate as alpha in VPA v1.4.0, beta in v1.5.0 and GA in v1.6.0. If you are planning a rollout in mid-2026, check the VPA version matrix rather than the December 2025 blog post.
apiVersion: autoscaling.k8s.io/v1
kind: VerticalPodAutoscaler
metadata:
name: my-vpa
spec:
updatePolicy:
updateMode: "InPlaceOrRecreate"
In this mode VPA tries in-place first and falls back to recreating the pod. It attempts an update when container requests fall outside the recommended bounds, when a quick OOM occurs, or when a pod has run more than 12 hours and the recommendation differs by more than 10%.
The fallback rules are the operationally important part. VPA recreates the pod when the resize is infeasible, when it has been deferred more than 5 minutes, when it has been in progress more than 1 hour, when the QoS class would change, or when memory limit downscaling is needed under a no-restart policy. Plan for eviction even in in-place mode.
VPA v1.7.0 adds two alpha features worth tracking. InPlace mode never evicts: it only attempts in-place updates and retries, tracking infeasible attempts so it does not loop forever. And CPU Startup Boost temporarily multiplies CPU during startup, then scales back down in place once the pod is Ready, which suits JVM services paying a JIT tax on boot.
Track these VPA metrics from day one:
| Metric | What it tells you |
|---|---|
vpa_updater_in_place_updatable_pods_total |
Pods matching in-place criteria |
vpa_updater_in_place_updated_pods_total |
Pods successfully resized in place |
vpa_updater_failed_in_place_update_attempts_total |
Failed attempts, your fallback rate |
vpa_updater_vpas_with_in_place_updated_pods_total |
VPAs actually landing in-place updates |
If failed_in_place_update_attempts_total climbs, you are not running vertical autoscaling. You are running eviction with extra steps.
One more flag: --in-place-skip-disruption-budget (default false) lets VPA skip disruption budget checks when every container in the pod uses NotRequired for both CPU and memory. Budgets still apply the moment any container asks for RestartContainer, or when the update falls back to recreation.
Managed clusters: can you actually use this today?
Both releases are available on the major managed platforms. Amazon EKS lists Kubernetes 1.35 and 1.36 in standard support, and its release notes call out In-Place Pod Resource Updates as stable in 1.35. The Kubernetes project maintains release branches for the three most recent minor releases, currently 1.36, 1.35 and 1.34.
Three upgrade constraints in the same releases interact with this feature, and they are easy to hit in sequence.
The first is cgroup v1, which is gone in 1.35. The kubelet refuses to start by default on cgroup v1 nodes. Amazon Linux 2023 already defaults to cgroup v2. Bottlerocket 1.35 defaults to cgroup v2 but sets failCgroupV1: false for backward compatibility. AWS documents that Fargate continues to use cgroup v1, and pod-level in-place resize requires cgroup v2, so check your Fargate profiles before you plan a pod-level rollout around them.
The second is containerd. AWS states 1.35 is the last release supporting containerd 1.x and you must move to containerd 2.0 or later before the next upgrade. Pod-level resize wants containerd v2.0+ anyway for the UpdateContainerResources CRI call, so these two migrations belong in the same change window.
The third is that 1.36 carries unrelated breaking changes that will dominate your upgrade risk register: the gitRepo volume type is permanently disabled, strict IP and CIDR validation is on by default, and SELinux volume labelling changes default behaviour. None of these are about resize, but they decide whether your 1.36 upgrade lands.
The honest sequencing for most teams: get to cgroup v2 and containerd 2.0, land on 1.35, adopt container-level resize because it is stable there, and treat pod-level resize as a 1.36 follow-on once the beta has more mileage.
A rollout plan that does not page anyone
Adopt this in the order that fails cheaply.
- Confirm the substrate: Kubernetes 1.35+, cgroup v2, containerd 2.0+ or CRI-O, Linux nodes, kubectl v1.32+. Exclude Windows pools and anything pinned by the static CPU manager now, not after an incident.
- Set explicit resize policies. Use
NotRequiredfor CPU,RestartContainerfor memory on any JVM or CPython service. Do not rely on the default; be explicit so the next engineer can read intent. - Start with CPU only, on stateless services. CPU is where the no-restart path is real, and where the 69% over-provisioning figure concentrates.
- Run VPA in recommendation mode first. Read the recommendations for two to four weeks against real traffic before letting anything actuate.
- Switch a low-risk namespace to
InPlaceOrRecreate. Watchvpa_updater_failed_in_place_update_attempts_totaland your fallback rate. A high fallback rate means the node pool cannot fit the recommendations, which is a capacity problem, not a resize problem. - Only then touch memory. Memory decreases are permitted since 1.35 but the OOM protection is best-effort. Decrease in small steps and watch
PodResizeInProgressconditions that stall. - Verify the bill. Confirm the cluster autoscaler removed nodes. If node count did not drop, you saved nothing.
India-specific considerations
For teams running Kubernetes from Mumbai, Hyderabad, Delhi or Pune, three things change the calculation.
Cloud is billed in dollars and paid in rupees, so exchange movement raises the bill even when usage is flat. That makes structural waste more expensive here than the dollar figures suggest, and it makes reclaimed capacity worth more than an equivalent rate discount you cannot renegotiate. The 69% CPU over-provisioning figure is a rupee problem before it is an engineering one.
Data residency shapes which regions and node pools you can use, and the Digital Personal Data Protection Act 2023, which received presidential assent on 11 August 2023, governs how long personal data is retained. Resize does not touch residency directly, but the consolidation that follows rightsizing does: if bin-packing moves workloads across regions or accounts, residency has to be settled before the cost model, not after. We design applications aligned with DPDP Act 2023 requirements for exactly this reason.
Team structure is the third. Indian product teams rarely staff a dedicated FinOps role early, which is what makes an autoscaler-driven approach attractive: VPA in InPlaceOrRecreate enforces rightsizing continuously without a standing headcount reading dashboards. Our guide to cutting cloud spend for Indian teams covers the wider lever set this fits into, and our note on GPU spend as the top FinOps concern covers the accelerator side, where idle capacity costs dollars per hour rather than cents. Teams weighing whether to run this in-house can compare our managed Kubernetes and AI platform service and our cloud FinOps managed service.
The honest verdict
In-place pod resize is stable, it works, and CPU rightsizing without restarts is a real capability that did not exist in a supported form 12 months ago. It is also narrower than the headline suggests. Memory, which is where 79% over-provisioning sits, still restarts most real runtimes. The feature is a building block for autoscalers, not an operator you install.
The teams that get value from it will be the ones already on cgroup v2 and containerd 2.0, already running VPA in recommendation mode, and already able to tell whether a node count dropped. Everyone else has upgrade work to do first, and that work is where the schedule actually goes.
FAQ
What Kubernetes version made in-place pod resize generally available?
In-place pod resize graduated to stable in Kubernetes v1.35, announced on 19 December 2025. It was alpha in v1.27 in May 2023 and beta in v1.33 in May 2025. Kubernetes v1.36 later added beta support for in-place vertical scaling of pod-level resources, which was released on 22 April 2026.
Does resizing a pod always avoid a container restart?
No. Restart behaviour depends on the container's resizePolicy for each resource. With restartPolicy set to NotRequired, which is the default, CPU changes apply to the running container. With RestartContainer, the container restarts. Memory usually needs RestartContainer because Java and Python runtimes cannot resize their heap without restarting.
Can I decrease a memory limit on a running container?
Yes, since Kubernetes v1.35 lifted the previous prohibition. The kubelet only allows the decrease if current memory usage is below the new limit, and it skips the resize otherwise. The Kubernetes maintainers describe this OOM protection as best-effort, because usage can spike immediately after the check completes.
Which workloads cannot use in-place pod resize?
Windows pods are unsupported. Pods managed by static CPU or Memory manager policies cannot resize in place. Pods using swap cannot resize memory requests unless the memory policy is RestartContainer. Non-restartable init containers and ephemeral containers cannot be resized, though sidecar containers can. Only CPU and memory are resizable.
What does PodResizePending with reason Deferred mean?
It means the kubelet cannot apply the resize now but may later, for example once another pod is removed. The kubelet retries automatically. Deferred resizes are prioritised by PriorityClass first, then QoS class with Guaranteed before Burstable, and finally by how long the request has been waiting.
How much CPU are Kubernetes clusters actually wasting?
Cast AI's 2026 report measured average CPU utilisation at 8% and memory at 20% across tens of thousands of production clusters on AWS, GCP and Azure before optimisation. CPU over-provisioning rose from 40% to 69% year over year, and memory over-provisioning reached 79%, meaning most provisioned capacity is never even requested.
Is the Vertical Pod Autoscaler in-place mode production ready?
VPA's InPlaceOrRecreate mode reached GA in VPA v1.6.0, after alpha in v1.4.0 and beta in v1.5.0. It attempts in-place updates first and falls back to recreating the pod when a resize is infeasible, deferred beyond 5 minutes, in progress beyond 1 hour, or would change the QoS class.
Do I need cgroup v2 for in-place pod resize?
Pod-level in-place vertical scaling in v1.36 requires cgroup v2 and a runtime supporting the UpdateContainerResources CRI call, such as containerd v2.0 or later. Kubernetes v1.35 separately removed cgroup v1 support, so the kubelet refuses to start by default on cgroup v1 nodes regardless of resize.
How eCorpIT can help
eCorpIT is a CMMI Level 5, MSME-certified, senior-led engineering organisation in Gurugram that runs Kubernetes platform and cloud cost work for Indian and global teams. We audit resize readiness across your node pools, sequence the cgroup v2 and containerd 2.0 migrations that gate the feature, and roll out VPA in recommendation mode before anything actuates in production. We design applications aligned with DPDP Act 2023 requirements, so residency and retention are settled before consolidation moves workloads. To scope a Kubernetes rightsizing review, contact our team.
References
- Kubernetes 1.35: In-Place Pod Resize Graduates to Stable - Natasha Sarkar, Kubernetes Blog, 19 December 2025.
- Kubernetes v1.36: In-Place Vertical Scaling for Pod-Level Resources Graduates to Beta - Kubernetes Blog, 30 April 2026.
- Resize CPU and Memory Resources assigned to Containers - Kubernetes Documentation.
- Resize CPU and Memory Resources assigned to Pods - Kubernetes Documentation.
- Kubernetes Release History - Kubernetes.
- Kubernetes v1.33: In-Place Pod Resize Graduated to Beta - Kubernetes Blog, 16 May 2025.
- Kubernetes 1.27: In-place Resource Resize for Kubernetes Pods (alpha) - Kubernetes Blog, 12 May 2023.
- In-Place Update of Pod Resources (KEP-1287) - Kubernetes Enhancements.
- Review release notes for Kubernetes versions on standard support - Amazon EKS User Guide.
- Vertical Pod Autoscaler features documentation - kubernetes/autoscaler.
- 2026 State of Kubernetes Resource Optimization: CPU at 8%, Memory at 20%, and Getting Worse - Laurent Gil, Cast AI, 21 April 2026.
- Cast AI's 2026 State of Kubernetes Optimization Report Reveals GPU Utilization at 5% - Cast AI press release, 21 April 2026.
- m7i.xlarge pricing and specs - Vantage EC2 instance pricing.
- Kubernetes v1.35: Timbernetes (The World Tree Release) - Kubernetes Blog, 17 December 2025.
- The Digital Personal Data Protection Act, 2023 - Ministry of Electronics and Information Technology, Government of India.
Last updated: 16 July 2026.
Top comments (0)