The resource isolation layer underneath your containers just changed
cgroups are not optional plumbing. They are the mechanism that makes container resource management real: CPU limits, memory boundaries, I/O accounting. Without them, a container is just an isolated filesystem view with no enforceable resource constraints. The kernel has supported two generations of this mechanism, and Kubernetes has now drawn a hard line between them.
Kubernetes 1.36, released on 22 April 2026, removed cgroup v1 support entirely. Not deprecated, not disabled by default: removed. If your nodes are still running in cgroup v1 mode when you upgrade, the kubelet will not start. The migration must happen at the node level, before the Kubernetes upgrade, and it touches GRUB parameters, the container runtime configuration, and kubelet config simultaneously.
This post walks through what changed architecturally, what the removal timeline actually looks like version by version, and what your team needs to audit before touching a cluster upgrade.
cgroup v1 vs cgroup v2: the architectural difference that matters
cgroups first appeared in Linux 2.6.24 in 2008, developed by engineers at Google for large-scale resource management. The v1 design gave each resource controller its own independent hierarchy tree. A process could belong to a cgroup called web-server for memory limits and a completely separate cgroup called high-priority for CPU limits. That sounds flexible; in practice it was a source of persistent accounting bugs.
The clearest example: the blkio controller had no visibility into which memory cgroup a process belonged to. When the kernel swapped a page to disk, the I/O was charged to the root cgroup, bypassing the container’s I/O limits entirely. Resource enforcement looked correct at the controller level and was wrong at the system level.
cgroup v2 replaced the fragmented hierarchy with a single unified tree. A process belongs to exactly one cgroup. All controllers (CPU, memory, IO) are enabled on that single node. The kernel always knows which cgroup is responsible for a resource action, which closes the accounting gap that made v1 I/O limits unreliable.
In cgroup v1, the blkio controller had no idea which memory cgroup a process belonged to. When the kernel swapped a page to disk, the I/O was charged to the root cgroup, bypassing the container’s limits entirely. cgroup v2 closes that gap by enforcing a single hierarchy where all controllers share the same process membership.
Interface changes that will break your tooling
The architectural shift comes with concrete interface removals that affect both runtimes and observability tooling. Teams that have built custom resource accounting or network policy tooling on top of cgroup v1 interfaces need to audit those integrations specifically.
- The
cpuacctsubsystem is gone in v2; CPU accounting is now handled by thecpusubsystem directly. - The
freezersubsystem is removed; the equivalent iscgroup.freezein the v2 general interface. - The
net_clsandnet_priointerfaces do not exist in v2; network traffic filtering and shaping moves to eBPF. - In v2, processes can only be attached to leaf cgroups. A cgroup that has child cgroups cannot directly contain processes, which eliminates ambiguous parent-child process membership from v1.
On the positive side, v2 brings capabilities that v1 could not support cleanly: Pressure Stall Information for CPU, memory, and IO; unified accounting for network memory and kernel memory alongside anonymous memory; and the MemoryQoS feature, which improves memory quality-of-service guarantees using v2 primitives directly.
The removal timeline, version by version
The deprecation followed a deliberate phased approach across several releases. Understanding the sequence matters because teams on extended support cycles or slow upgrade cadences may be closer to the hard wall than they realise.
- Kubernetes 1.25: cgroup v2 support graduates to GA. This is when it became safe to run v2 in production.
- Kubernetes 1.31: cgroup v1 enters maintenance mode under KEP-4569. No new features; existing functionality frozen.
- Kubernetes 1.35: The
failCgroupV1kubelet flag defaults totrue. The kubelet fails to start if cgroup v2 is not detected on the node. This is KEP-5573 reaching beta. - Kubernetes 1.36 (released 22 April 2026): cgroup v1 support fully removed. Nodes still in v1 mode cannot run this release at all.
- Kubernetes 1.38: Earliest date for removal of cgroup v1 code from the codebase itself, per KEP-5573, to maintain the Kubernetes deprecation policy.
The practical implication of the 1.35 change is that teams who had not migrated yet received a forcing function: upgrade to 1.35 and the kubelet tells you explicitly that your node configuration is incompatible. Upgrade to 1.36 without fixing it and the node simply does not come up.
What a node-level migration actually requires
The migration is not a Kubernetes configuration change. It is a host-level operation that must be completed before the cluster upgrade, and it has three components that need to be consistent with each other.
Kernel boot parameter: The node must boot with the unified cgroup hierarchy enabled. On most distributions this means adding systemd.unified_cgroup_hierarchy=1 to the kernel command line in GRUB and rebooting. On distributions shipping with cgroup v2 as default (recent Fedora, RHEL 9, Ubuntu 22.04 and later, Debian 11 and later), this is already set. On older LTS images it is not.
Container runtime configuration: containerd must be configured to use the systemd cgroup driver. In /etc/containerd/config.toml, the relevant section is [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] with SystemdCgroup = true. Docker-based setups require the equivalent change to the Docker daemon configuration.
Kubelet configuration: The kubelet must also be set to use the systemd cgroup driver. In the KubeletConfiguration object, cgroupDriver: systemd. The kubelet and the container runtime must agree on the driver; a mismatch causes pod creation failures that are difficult to diagnose after the fact.
After the reboot, verify the active hierarchy with stat -fc %T /sys/fs/cgroup/. The output should be cgroup2fs. If it returns tmpfs, the node is still on v1.
Where infrastructure control actually matters here
This migration is straightforward on infrastructure where you control the host. On managed hyperscaler Kubernetes services, the node image, kernel version, cgroup configuration, and boot parameters are abstracted away. You upgrade the control plane version and hope the managed node pool images are already compliant. When they are not, the remediation path runs through the provider’s support queue rather than your own tooling.
On DIVERSITY’s bare-metal and VDS environments, our customers have direct access to kernel and cgroup configuration at the node level, which is exactly the control surface this migration requires. Our IT Consulting team has been working through cgroup v2 migration audits with customers running containerised workloads across our infrastructure, validating kernel versions, containerd configurations, and kubelet driver alignment before the 1.36 cutover.
The audit checklist for any team running Kubernetes today should cover: the kernel version on each node type (v2 requires Linux 4.15 minimum, with full feature support from 5.8 onwards); the distribution default for cgroup hierarchy; the containerd or CRI-O version and its cgroup driver setting; any custom resource accounting tooling built against v1 interfaces; and any DaemonSets or node-level agents that interact with the cgroup filesystem directly.
Timing your upgrade
If you are running Kubernetes 1.31 through 1.34, you are on a release that still supports v1 but has frozen it. You have time to migrate the nodes before upgrading, which is the correct order of operations. If you are already on 1.35, the failCgroupV1 flag is your signal: any node that failed to start after the upgrade is telling you exactly which hosts need remediation. Do not suppress the flag to restore availability; fix the node configuration and let the kubelet validate it properly.
Teams on 1.36 or planning to move there have no fallback. The code is gone. The migration is a prerequisite, not a follow-up task.
cgroup v2 is not new. It has been the default on major Linux distributions for several years, and Kubernetes has supported it at GA since 1.25. The deprecation timeline was long and well-signalled. What the 1.36 release does is remove the option to defer, and that is worth treating as the forcing function it was designed to be.




