deniz.in

Markets

Weather

Loading weather

· via dev.to (home feed)

Kubernetes 1.35 in-place pod resize is GA, but JVM and Node heaps don't grow with it

In-place pod resize is generally available in Kubernetes 1.35. CPU changes apply live, but hands-on testing shows JVM and Node.js heaps stay sized to their startup limits unless the container restarts.

Kubernetes 1.35 in-place pod resize is GA, but JVM and Node heaps don't grow with it

In-place pod resize reached general availability in Kubernetes 1.35, and hands-on testing published on dev.to confirms the headline claim: CPU limits on a running pod can be raised with a single patch, with no restart and no rescheduling. The same testing also surfaced a gap that matters more in practice. Runtimes such as the JVM and Node.js size their heaps once, at startup, and never revisit that number, so a memory resize that looks successful can leave an application crashing against a limit it calculated minutes earlier.

CPU resizes apply within seconds

According to the dev.to post, the author ran a Node 22 service and a Java 21 service on a kind cluster running Kubernetes 1.37 and drove load at both while resizing them. Patching the pod's resize subresource lifted the Node app from a 200m CPU limit to 2 cores. Inside the container, the cgroup's cpu.max value changed 0.27 seconds after the patch returned, the restart count stayed at zero, and throughput roughly tripled from around 11 requests per second to 33, with p99 latency falling from about 1.5 seconds to roughly 420 milliseconds.

Two caveats emerged from the same test. The Node process used only one of its two cores, because a single-threaded event loop cannot use more — extra CPU helps such a service only up to one full core. And runtimes report available CPU differently: the JVM reads the cgroup quota live and rounds up, while Node's libuv reports the host's full core count whenever the quota is below one whole core. A worker pool sized from that number is therefore most wrong in the smallest pods.

Runtimes do not see the new memory

Memory is where the feature breaks down at the application layer. A Java 21 pod started with a 512Mi limit sized its heap to about 123 MB. After a resize to 2Gi, the cgroup updated within seconds, but the heap stayed at 123 MB, because MaxHeapSize is computed once at process start. When the app was asked to allocate 200 MB, it threw an OutOfMemoryError with 1.9 GB of headroom unused. The kernel never intervened, because from its perspective nothing was wrong.

Node behaved similarly. Under a 256Mi limit its heap cap came out at 259 MB; after a resize to 1Gi, allocating 400 MB of objects triggered a fatal JavaScript heap error, the process exited with code 139, and the container restarted, generating 1,853 failed requests during the recovery window. Only after that restart did the heap report 524 MB.

resizePolicy decides what restarts

The dev.to author points to resizePolicy as Kubernetes' answer to this. Each resource can carry a restartPolicy of NotRequired or RestartContainer, so a common configuration applies CPU changes live while restarting only the container — not the pod — on memory changes. In the test, a 512Mi-to-2Gi resize under that policy kept the same pod and IP, brought the container back to ready in about one second, and relaunched the JVM with a 494 MB heap. The event log states plainly that the container was killed because the resize required it.

Shrinking and rejections

Shrinking memory behaved better than expected: a 2Gi-to-200Mi reduction applied within a second with no restart. But lowering the limit below current usage — 100Mi against roughly 160 MB in use — was refused by the kubelet, which left the cgroup at 200Mi, kept the pod running, and set a PodResizeInProgress condition with reason Error that kept retrying until the request was changed. That failure surfaces only in a pod condition that most dashboards do not display. Separately, requesting more than a node can allocate, such as 64 CPUs on a 16-core node, is rejected by the API server at patch time rather than leaving the pod pending.

Why it matters

General availability of in-place resize removes one of Kubernetes' oldest operational frictions: changing a workload's resources no longer requires a rollout. For CPU-bound services this is now a live operation measured in seconds. The memory side is the trap. Every conventional signal — the pod spec, the cgroup, usage graphs — will say the resize worked while the application dies against a startup-era limit. The practical advice from the dev.to testing is to treat RestartContainer as the sensible default for memory unless you have verified your runtime can grow its heap, and to watch pod resize conditions, since a rejected shrink otherwise fails quietly.

  • #kubernetes
  • #containers
  • #cloud
  • #jvm
  • #node-js

Related posts