Kubernetes 1.35: In-Place Pod Resize Is GA, and cgroup v1 Nodes Stop Booting
โ kubernetes, k8s-1.35, release-notes, in-place-resize, cgroup, cloud-native โ 11 min read
The question that matters for Kubernetes 1.35 is simple: should you take the upgrade now? The case for yes is one clearly useful feature. In-place Pod resize is finally GA, so you can change a Pod's CPU and memory without restarting it. The case for caution is one clearly disruptive change. Nodes running the legacy cgroup v1 will refuse to start the kubelet by default. This post weighs both, plus the deprecations that turn 1.35 into a hard deadline for containerd 1.x and Ingress-NGINX, and ends with a verdict.
Previous release: Kubernetes 1.34. Next: 1.36 (coming soon).
Here is what you are deciding on, at a glance:
- In-place Pod resize is GA (KEP #1287). You can resize CPU and memory on a running Pod. Only CPU and memory are allowed.
- cgroup v1 is effectively cut off. From 1.35 the kubelet sets
failCgroupV1: trueby default, so a node on cgroup v1 will not start the kubelet. Migrate nodes to cgroup v2, or setfailCgroupV1: falseas a temporary escape hatch. - 1.35 is the last release to support containerd 1.x. Move to containerd 2.0+ before you upgrade to 1.36.
- Image volumes are on by default (KEP #4639), but need containerd 2.1 or later.
- Deprecations to note: ipvs mode in kube-proxy (migrate to nftables) and the Ingress-NGINX controller (best-effort until March 2026, then archived; move to Gateway API).
- Upgrade warning: the kubelet flag
--pod-infra-container-imagewas removed, and theStorageVersionMigrationandVolumeAttributesClassv1alpha1APIs were removed.
In-place Pod resize is the reason to upgrade
Start with what earns the upgrade: workload right-sizing. For years, changing a Pod's resources meant deleting and recreating it, which is disruptive for stateful and long-running jobs. In-place resize removes that constraint and reaches GA in 1.35.
Before this, changing a container's CPU or memory request meant the scheduler replaced the Pod. In-place resize, GA in 1.35, lets the kubelet apply the new resources to the running Pod through a dedicated resize subresource (KEP #1287, changelog).
The lifecycle, from request to applied, is a small state machine.
[ Pod running ] โ kubectl patch --subresource resize โผ[ PodResizePending ] โโโถ [ PodResizeInProgress ] โโโถ [ Pod running, new resources ] (validated) (kubelet actuates) (no restart)Caption: in-place resize moves a Pod through pending and in-progress states without recreation.
Patch the resize subresource to change resources on a live Pod:
kubectl patch pod mypod --subresource resize --patch \ '{"spec":{"containers":[{"name":"app","resources":{"requests":{"cpu":"1","memory":"1Gi"}}}]}}'Notice two limits from the changelog: only CPU and memory can be resized, and the change is tracked in new PodStatus fields (Resources, AllocatedResources). Memory decreases are now supported, which was the hard case.
Adopt now for stateful workloads and long-running jobs that need to scale without downtime. Watch the PodResizePending and PodResizeInProgress conditions rather than assuming the patch applied instantly.
Why resize took eight years to land
In-place resize took eight years to reach GA (alpha in 1.27) because the hard parts are not the API. Shrinking a memory limit on a running process is not always safe, since you cannot force a process to give memory back. The GA design handles this by tracking desired versus allocated resources in PodStatus and letting the kubelet actuate when it can, rather than guaranteeing an instant change. That is why you watch PodResizeInProgress instead of assuming the patch took effect. The scope was also deliberately kept to CPU and memory; extending it to other resources like GPUs is future work (KEP #1287).
The upgrades you will quietly appreciate
The rest of 1.35 is less dramatic but worth knowing before you commit.
Image volumes are on by default Beta
Image volumes let a Pod mount an OCI (Open Container Initiative) artifact or image as a read-only volume, so you can ship configs, binaries, or ML models separately from the app image and skip init containers (KEP #4639). Beta since 1.33, they are enabled by default in 1.35.
volumes:- name: model image: reference: registry.example.com/models/llama:v1 pullPolicy: IfNotPresentvolumeMounts:- name: model mountPath: /modelsNotice the requirement: this needs containerd 2.1 or later. On older runtimes the volume will not mount.
Pod certificates for workload identity Beta
Workload identity inside a cluster has leaned on ServiceAccount tokens, which are awkward for mutual TLS. In 1.35 the kubelet can generate a key, request a certificate through a PodCertificateRequest, and write the bundle into the Pod's filesystem, with automated rotation (KEP #4317). Beta.
Adopt if you need certificate-based, per-Pod identity for mTLS between services.
PreferSameNode traffic distribution is GA GA
This completes the story 1.34 started. The Service trafficDistribution field gains PreferSameNode (prefer an endpoint on the same node, fall back to remote) at GA, and the old PreferClose value is now the alias PreferSameZone (KEP #3015).
apiVersion: v1kind: Servicespec: trafficDistribution: PreferSameNodeNotice PreferSameNode cuts a network hop for node-local traffic; use PreferSameZone when you only need to stay in-zone.
Reliable Pod and Deployment status tracking GA Beta
Two observability fixes. Pods now increment .metadata.generation on every spec change and report .status.observedGeneration, so controllers can tell whether the kubelet has processed the latest spec (KEP #5067, GA). Deployments gain a beta .status.terminatingReplicas count, so you can distinguish a stable Deployment from one still cleaning up Pods.
Adopt: nothing required. These make automation and dashboards more accurate.
Job managed-by mechanism is GA GA
The Job .spec.managedBy field lets an external controller own a Job's status sync instead of the built-in controller (KEP #4368). This is the foundation for MultiKueue, which schedules Jobs across clusters. Adopt if you run multi-cluster batch with Kueue.
KYAML is on by default Beta
KYAML, the safer YAML subset introduced as alpha in 1.34, is beta and enabled by default in 1.35 (KEP #5295). kubectl get -o kyaml works out of the box; set KUBECTL_KYAML=false to disable. Every KYAML file is valid YAML, so nothing downstream breaks.
Batch and AI: gang scheduling and user namespaces Alpha Beta
Two items for AI and batch. Gang scheduling arrives as alpha through a Workload API and PodGroup, giving all-or-nothing scheduling so a distributed job either gets all its Pods or none (KEP #4671). User namespaces continue in beta, mapping container user and group IDs to unprivileged host ranges (KEP #127). Adopt gang scheduling only on test clusters for now; it is alpha.
Smoother kubelet restarts Behaviour change
A quieter but welcome fix: restarting the kubelet no longer flaps healthy Pods to NotReady. The kubelet now restores container state from the runtime on startup, so traffic keeps flowing during node maintenance (release blog). Nothing to configure.
What will break when you upgrade
Now the other side of the decision: what 1.35 takes away. The theme is retiring old foundations. cgroup v1, the first Linux control-group interface, has been superseded by cgroup v2 since 1.25. Supporting both was a maintenance drag and a source of inconsistent resource behaviour. containerd 1.x and the ipvs kube-proxy backend are in the same category. 1.35 draws a line under all three so the project can focus on the modern replacements. Read this section before upgrading.
cgroup v1 nodes will not start the kubelet Behaviour change
This is the change most likely to bite you, so it appears here and in the deprecations section. From 1.35 the kubelet defaults failCgroupV1 to true, meaning it refuses to start on a node using cgroup v1 (changelog, KEP #5573).
kubelet starts on a node โ cgroup v2? โโโโโโดโโโโโ yes no โ โ start failCgroupV1=true (default) โโโถ kubelet refuses to start โ failCgroupV1=false โโโถ starts, with cgroup v1 (temporary)Caption: on 1.35 a cgroup v1 node needs an explicit override to run the kubelet.
The fix is to migrate nodes to cgroup v2, available since 1.25. If you need a short reprieve, set failCgroupV1: false in the kubelet configuration (for kubeadm, the kube-system/kubelet-config ConfigMap). Treat that as temporary; cgroup v1 is on its way out.
Adopt: check every node's cgroup version before upgrading. This is a boot-time failure, not a warning.
The removals and deadlines are wider than cgroup v1. 1.35 removes several APIs and flags and sets three deadlines.
Removed in 1.35
| Item | Replacement | Action | Source |
|---|---|---|---|
kubelet flag --pod-infra-container-image | Runtime-managed sandbox image | Remove the flag from kubelet args before upgrade or the kubelet fails to start | changelog |
StorageVersionMigration v1alpha1 API | v1beta1 | Delete v1alpha1 resources before upgrading | changelog |
VolumeAttributesClass in storage.k8s.io/v1alpha1 | storage.k8s.io/v1 (GA in 1.34) | Move to the v1 API | changelog |
Feature gates SizeMemoryBackedVolumes, ComponentSLIs, UserNamespacesPodSecurityStandards, StrictCostEnforcementForVAP/Webhooks (all GA) | Behaviour is permanent | Remove any gate overrides | changelog |
Env var KUBECTL_OPENAPIV3_PATCH | None | Remove if set | changelog |
Deprecated in 1.35 (removed later)
Note on containerd: the 1.35 release blog stated the removal would land in 1.36. It has since slipped twice (1.36 deferred it to 1.37, and 1.37 deferred it to 1.38), aligned with containerd 1.7 end of support. Do the containerd 2.0 migration now, but verify the actual removal in the target release's changelog rather than trusting the announced version.
| Item | Target removal | Replacement | Action | Source |
|---|---|---|---|---|
cgroup v1 (kubelet default failCgroupV1: true) | Being retired | cgroup v2 | Migrate nodes to cgroup v2 | KEP #5573 |
| containerd 1.x support | Removed in 1.37 (see note) | containerd 2.0+ | Upgrade the runtime; watch kubelet_cri_losing_support | release blog |
kube-proxy ipvs mode | Future release | nftables mode | Migrate the kube-proxy backend | KEP #5495 |
| Ingress-NGINX controller | Archived after March 2026 | Gateway API | Plan migration to Gateway API | Ingress-NGINX retirement |
To find nodes still on cgroup v1 before you upgrade, check the node's cgroup mount:
kubectl get nodes -o name | while read n; do echo "$n"; kubectl debug "$n" -it --image=busybox -- \ sh -c 'stat -fc %T /sys/fs/cgroup' 2>/dev/nulldoneNotice cgroup2fs means cgroup v2 (fine); tmpfs means cgroup v1 (must migrate). Adjust for your node-access method.
To find Services still using the old traffic value:
kubectl get svc -A -o json \ | jq -r '.items[] | select(.spec.trafficDistribution=="PreferClose") | "\(.metadata.namespace)/\(.metadata.name)"'Notice these should move to PreferSameZone.
The changes that fail closed
From the changelog's Urgent Upgrade Notes and deprecation section:
- cgroup v1 kubelet refuses to start.
failCgroupV1defaults totrue. A cgroup v1 node will not run the 1.35 kubelet withoutfailCgroupV1: false. kubeadm'sSystemVerificationpreflight also errors on cgroup v1 with a 1.35 kubelet. --pod-infra-container-imageremoved. Non-kubeadm clusters must strip this flag from kubelet config before upgrading, or the kubelet will not start. kubeadm clusters must remove it fromextraArgs.v1alpha1API removals.StorageVersionMigrationandVolumeAttributesClassv1alpha1are gone. Delete any storedv1alpha1objects first.DynamicResourceAllocationgate is locked on. GA in 1.34, it can no longer be disabled.- KYAML and image volumes default on. KYAML output is default (disable with
KUBECTL_KYAML=false); image volumes need containerd 2.1+. - In-place resize is CPU and memory only. Attempts to resize other resource types are rejected.
Version skew rules are unchanged: upgrade the control plane before nodes, and keep the kubelet within the supported skew of the API server (version skew policy).
Sequencing the upgrade
With the trade-offs clear, here is a safe order.
1. inventory node cgroup versions โโโถ migrate cgroup v1 nodes to v22. remove --pod-infra-container-image from kubelet config3. delete v1alpha1 StorageVersionMigration / VolumeAttributesClass objects4. upgrade container runtime to containerd 2.0+ (last chance before 1.36)5. upgrade control plane6. upgrade nodes (kubelet, CRI); confirm kubelet starts (cgroup v2)7. keep 1.34 control-plane images for rollbackCaption: recommended 1.34 to 1.35 upgrade order.
Specifics:
- cgroup version is the first thing to check. A cgroup v1 node will hard-fail on the new kubelet.
- Remove
--pod-infra-container-imageeverywhere it appears. - Scan for
v1alpha1StorageVersionMigrationandVolumeAttributesClassobjects and remove them. - containerd 2.0+ is required before 1.36, so 1.35 is the natural time to do it.
- Rollback: keep 1.34 control-plane images. In-place resize is GA and backward compatible; a rollback does not strand resized Pods.
Try these on a test cluster
- Resize a running Pod:
kubectl patch pod <p> --subresource resize --patch '{"spec":{"containers":[{"name":"app","resources":{"requests":{"cpu":"500m"}}}]}}'and watch the conditions. - Check a node's cgroup version:
stat -fc %T /sys/fs/cgroup(expectcgroup2fs). - Mount an image volume (on containerd 2.1+) and read a file from it.
- Switch a test Service to
trafficDistribution: PreferSameNode. - Confirm KYAML output:
kubectl get deploy -o kyaml.
The call
So, is 1.35 worth taking now? Yes, provided you do the node work first. Kubernetes 1.35 gives you in-place Pod resize at GA and takes away cgroup v1. The must-do list is short and hard-edged: migrate cgroup v1 nodes, drop the removed kubelet flag, clear the v1alpha1 APIs, and move to containerd 2.0+ before 1.36. Start the Ingress-NGINX to Gateway API migration now, before the March 2026 archive date.
Next in this series: Kubernetes 1.36.
References
Release and dates:
Features:
- In-place resize: KEP #1287
- Pod certificates: KEP #4317
- Image volumes: KEP #4639
- Traffic distribution: KEP #3015
- Pod generation: KEP #5067; Job managedBy: KEP #4368
- KYAML: KEP #5295
- Gang scheduling: KEP #4671; user namespaces: KEP #127
Deprecations: