Skip to main content
BlogDevOps

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

How Kubernetes in-place pod resize changes CPU and memory on a running pod without a restart — the resize subresource, resizePolicy, and VPA InPlaceOrRecreate, from beta in v1.33 to GA in v1.35.

Matthews Wong

Software Engineer

August 20269 min read
Kubernetes In-Place Pod Resize: CPU & Memory No Restart

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 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: 512Mi

NotRequired 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 state

One 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:

AspectVPA Recreate (old way)In-place resize
DisruptionPod evicted and rescheduledRunning container reconfigured, usually no restart
In-memory stateLost on evictionPreserved when the policy is NotRequired
How it appliesDelete pod, scheduler recreatesMutate resources via the resize subresource
OverprovisioningEncouraged — restarts are costlyReduced — requests can track real usage
MaturityStable for yearsGA 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.

FAQ

Frequently Asked Questions

Short answers to what readers ask most about this topic.

What is Kubernetes in-place pod resize?

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.

Which Kubernetes version made in-place pod resize stable?

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.

How do I resize a running pod without restarting it?

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.

What does resizePolicy NotRequired versus RestartContainer do?

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.

How is VPA InPlaceOrRecreate different from the old Recreate mode?

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.