For the entire history of Kubernetes, changing a pod's CPU or memory envelope meant killing the pod. Every right-sizing — a tenant bumping past their plan's default limits, a recommender noticing chronic OOMKills, an autoscaler reacting to a traffic spike — ended the same way: evict, reschedule, cold-start. Kubernetes 1.36 closes that era for the pod as a whole: in-place vertical scaling for pod-level resources graduated to Beta in April 2026, enabled by default, following pod-level resources (beta in 1.34) and container-level in-place resize (GA in 1.35). The kubelet can now grow or shrink a running pod's aggregate resource budget with a single API write, usually without restarting a single container.
The artifact up front: here is the whole operation. A pod defined with a 2-CPU shared pool gets doubled to 4 CPUs while it keeps serving traffic:
kubectl patch pod shared-pool-app --subresource resize --patch \
'{"spec":{"resources":{"limits":{"cpu":"4"}}}}'No new pod name, no rescheduling, no RESTARTS counter increment — the pod keeps its identity and its connections while the kubelet rewrites the cgroup limits underneath it. The rest of this post covers how that write is actually applied, what it replaces inside a PaaS autoscaler, and the beta caveats to clear before wiring it into production.
How the kubelet actually applies a resize
Patching the resize subresource only updates desired state. The kubelet then runs an admission and actuation sequence that operators need to understand, because every step has an observable failure mode.
1. Feasibility check against node allocatable. Before touching any cgroup, the kubelet verifies the new aggregate request fits in the node's remaining allocatable capacity. If the node is overcommitted, the resize is not silently dropped: the PodResizePending condition reports Deferred or Infeasible, telling you exactly why the envelope hasn't grown. This is the first thing to internalize — a resize is an admission decision made by the kubelet against local headroom, not by the scheduler against the cluster. The scheduler placed your pod at its old size and does not re-evaluate placement when it grows, which means aggressive in-place growth can fragment scheduler accounting on a densely packed node.
2. Ordered cgroup sequencing. To avoid transient overshoot, the kubelet updates cgroups in a fixed order: when scaling up, the pod-level cgroup expands first to create room, then individual container cgroups grow into it; when scaling down, container cgroups are throttled first and only then does the aggregate pod cgroup shrink. Expand-then-fill on the way up, drain-then-shrink on the way down.
3. Observable status, not a black box. Beta-grade observability rides on pod conditions and two status fields: status.allocatedResources (what the node admitted) versus status.resources (what is actually applied to the cgroups). While those two disagree, PodResizeInProgress reads True. A PaaS can — and should — surface these conditions in tenant-facing status instead of making users guess whether their plan bump took effect.
4. Per-container restart policy still rules. There is no resizePolicy at the pod level; the kubelet defers to each container's own policy. A container with NotRequired gets a live cgroup update via the CRI's UpdateContainerResources call; a container with RestartContainer is restarted to apply the new boundary safely. When pod-level limits grow, every container inheriting from the shared pool is evaluated this way — one RestartContainer sidecar in the pod means that sidecar bounces even though the main app doesn't.
What this replaces in a PaaS autoscaler: a before/after
The traditional vertical-autoscaling path in a git-push PaaS is restart-on-resize: the recommender (VPA in Auto mode, or homegrown logic) computes new requests, evicts the pod, and the workload controller recreates it at the new size. That path carries real costs — cold starts (JVM warmup, dropped connections, emptied caches), PodDisruptionBudget checks, and surge capacity so the replacement lands somewhere. In-place resize deletes most of that machinery for the common case:
| Before: restart-on-resize | After: in-place actuation | |
|---|---|---|
| Tenant bumps plan limits | Evict + recreate; brief unavailability per replica | PATCH /resize; pod keeps name, IP, connections |
| Recommender right-sizing | New rollout per adjustment; churn during convergence | Cgroup rewrite; RESTARTS untouched |
| OOM-driven growth | Crash, then recreate bigger (loses in-memory state twice) | Grow the live pod before the next spike |
| Oversubscribed node | Scheduler finds a new node for the bigger pod | Resize reports Infeasible; falls back to recreate |
| Autoscaler code | Eviction orchestration, PDB handling, surge accounting | Resize call + condition watch + recreate fallback |
Two honest limits keep this from being a universal replacement. First, a resize the node cannot fit still recreates — VPA's InPlaceOrRecreate update mode (alpha in VPA v1.5.0, available on GKE 1.34+ and recommended by AKS docs) exists precisely because the fallback path is permanent, not transitional: growth beyond node headroom always needs a new placement. Second, large corrections still bounce: field experience shows big initial right-sizes (e.g., cutting requests 10x on a long-mis-sized pod) exceed what the kubelet will apply live — memory the process is actually using can't be throttled away — so VPA falls back to recreation and only subsequent incremental adjustments go in-place. Expect the recreate path to handle the first correction and the in-place path to handle steady-state drift.
The scheduler side is also still catching up: scheduler preemption for in-place pod resize only reached alpha in Kubernetes 1.37, so a resize that needs room today waits on headroom rather than preempting lower-priority pods to make it. Until that matures, keep the recreate fallback and don't promise tenants that every resize lands instantly.
The beta caveats checklist before production
Here is the explicit gate list — resource types, runtimes, and every other precondition — verified against the 1.36 announcement and KEP-1287:
| Check | Status in 1.36 | What to verify on your fleet |
|---|---|---|
| Resource types | CPU and memory only — no hugepages, no extended or custom resources | Resize calls touching anything else are rejected |
| Node cgroups | cgroup v2 only — required for accurate aggregate enforcement | Audit node images; a mixed v1/v2 fleet resizes inconsistently |
| Container runtime | Must implement CRI UpdateContainerResources (containerd v2.0+ or CRI-O) | Pin and verify runtime versions before enabling |
| OS | Linux-only | Windows node pools stay on restart-on-resize |
| Feature gates | PodLevelResources + InPlacePodVerticalScaling + InPlacePodLevelResourcesVerticalScaling + NodeDeclaredFeatures | All four on; the pod-level gate is default-on in 1.36 |
Pod-level resizePolicy | Not supported — kubelet defers to per-container policies | Set NotRequired/RestartContainer on every container, including sidecars |
| QoS class | Immutable across a resize — validation rejects any resize that would change Guaranteed/Burstable/BestEffort | Size the QoS shape at creation; resize can't fix a wrong class |
resizePolicy itself | Set it at pod creation; it can't be added to a running pod later | Bake it into your pod template now, not when you first resize |
| Memory decreases | Shrinking memory in use can fail or require restart semantics | Treat down-resizes as restart-candidates; test your workloads |
| VPA pod-level recommendations | Roadmap, not shipped — the stated focus for the GA push | Container-level VPA works; pod-budget recommendations don't exist yet |
The runtime and cgroup rows deserve emphasis because they are fleet-wide prerequisites, not per-workload flags: a single node image still on cgroup v1 or an older containerd turns resize into a per-node lottery. And the QoS row bites PaaS defaults hardest — if your platform launches every tenant pod as BestEffort or Burstable with loose requests, no amount of in-place resizing upgrades the QoS contract; that shape is chosen once, at creation.
What a self-hosted fleet should do now
For a Cluster-API-managed fleet on owned machines, where you control the node image and the runtime version, the adoption sequence is short:
- Verify the node baseline. Confirm images boot cgroup v2 and ship containerd v2.0+ or CRI-O with
UpdateContainerResourcessupport. This is one image audit, not a per-tenant migration. - Bake
resizePolicyinto the pod template. Every container your platform creates — app and sidecar alike — should carry an explicit policy from day one, since it can't be retrofitted onto running pods. - Expose resize conditions to tenants.
PodResizePendingandPodResizeInProgressbelong in your status surface next to restarts and OOMKills, so a deferred resize reads as "node full, queued" instead of a silent no-op. - Keep the recreate fallback. VPA's
InPlaceOrRecreateis the right model for homegrown autoscalers too: attempt the resize, watch the conditions, and recreate when the kubelet reportsInfeasibleor the delta is too large to apply live. - Track 1.37's resize preemption alpha. Once the scheduler can preempt to make room for a resize, the "node full" failure mode shrinks from a hard fallback to a scheduling delay — that's when in-place becomes the default path rather than the attempted one.
Conclusion: right-sizing stops being a deployment
The arc from alpha in 1.27 through beta in 1.33, container-level GA in 1.35, and now pod-level beta in 1.36 points in one direction: resource sizing is becoming a control-plane write, not a rollout. For a PaaS, that collapses an entire category of operational work — the eviction orchestration, disruption budgets, and surge math that exist only because changing a number required killing a process. The beta checklist above is real but bounded, and every item on it is verifiable in an afternoon against your own node images. The platforms that adopt in-place resize early won't just restart tenants less; they'll delete code paths that only existed to apologize for restarts.
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.



