Kubernetes has crossed an important boundary in its long migration from cgroup v1 to cgroup v2. Since Kubernetes 1.35, the kubelet’s failCgroupV1 setting defaults to true, which means a Linux node using the old control-group hierarchy will not start the kubelet under the default configuration. The Kubernetes project’s latest guidance also identifies version 1.38 as the planned point at which the fallback is removed.
That changes the operational meaning of cgroup v2. It is no longer an optional host modernization that can be postponed behind routine cluster upgrades. For platform teams, cgroup v1 has become an upgrade prerequisite with consequences across node images, container runtimes, observability agents, language runtimes and capacity planning.
The temporary escape hatch—setting failCgroupV1: false—can keep a legacy node running today. It should be treated as rollback insurance, not a migration strategy. The safer approach is to inventory the entire path from Linux kernel to workload runtime, canary a new node pool, and validate how applications interpret resource limits before advancing the control plane and kubelets.
Why the default failure matters
Kubernetes has supported cgroup v2 as stable since version 1.25, and cgroup v1 entered maintenance mode in 1.31. The new behavior in 1.35 is more forceful because it moves the incompatibility from documentation into startup. On a v1 host, the kubelet does not simply emit another warning; it refuses to run unless an administrator explicitly opts back into the deprecated path.
For kubeadm-managed clusters, the failure can surface even earlier. Kubernetes’ SystemVerification preflight check returns an error during kubeadm init, join and upgrade when it detects cgroup v1 with a 1.35-or-later kubelet. This is useful protection, but it also means an overlooked node-image setting can interrupt an otherwise well-rehearsed rollout.
The broader Linux ecosystem is moving in the same direction. The Kubernetes enhancement proposal notes that systemd has phased out legacy and hybrid cgroup hierarchies, RHEL 9 defaults to v2, RHEL 10 supports only v2, and Amazon Linux 2023 describes v1 as unsupported and not recommended. Kubernetes is therefore removing a compatibility layer around an interface that its dependencies and host operating systems are already abandoning.
The migration deadline is also clearer than it once was. The project says the cgroup v1 fallback remains available in Kubernetes 1.36 but is scheduled for removal in 1.38. That gives operators a limited window in which the override can aid rollback. Waiting until 1.38 eliminates that cushion and makes the node operating system migration part of the critical path for the Kubernetes upgrade itself.
Start with a fleet-wide inventory
The first task is not changing kubelet configuration. It is discovering which nodes, images and workloads still depend on cgroup v1. On each Linux node, stat -fc %T /sys/fs/cgroup/ returns cgroup2fs for cgroup v2 and tmpfs for v1. Platform teams should automate that check through their fleet-management system and record the result with the node’s OS image, kernel, container runtime and Kubernetes version.
A useful readiness inventory should answer at least these questions:
- Does every candidate node image enable the unified cgroup v2 hierarchy by default?
- Does the kernel meet Kubernetes’ documented minimum of 5.8, with 5.9 or later preferred for Memory QoS?
- Is the container runtime new enough for cgroup v2, and does it use the same cgroup driver as the kubelet?
- Which privileged agents or applications read
/sys/fs/cgroupdirectly? - Which workloads use language runtimes that may misread cgroup v2 limits?
Runtime support is broad but version-sensitive. Kubernetes documents cgroup v2 support in containerd 1.4 and later and CRI-O 1.20 and later. Automatic discovery of the runtime’s cgroup driver requires the RuntimeConfig CRI RPC, available in containerd 2.0 and later or CRI-O 1.28 and later. Without that discovery, operators must make sure the kubelet and runtime are configured consistently, preferably with the systemd driver on kubeadm-managed systems.
The hidden risk sits above the node
A node that joins successfully is necessary evidence, but it is not sufficient. cgroup v2 presents a different filesystem API, and software that reads control-group files directly can produce incorrect metrics, calculate the wrong heap size or fail outright even when Kubernetes and the container runtime are healthy.
Monitoring and security agents deserve special attention because they commonly run as privileged DaemonSets and inspect host state. Kubernetes recommends cAdvisor 0.43.0 or later for standalone deployments. Every node-level profiler, policy agent and cost collector should be checked against its vendor’s cgroup v2 support statement, then exercised on the canary pool. A dashboard that quietly reports host memory instead of container memory can be more dangerous than a visible crash.
Application runtimes also matter. Kubernetes’ migration documentation recommends OpenJDK builds with full cgroup v2 support, including 8u372 and 11.0.16 or later. Node.js added reliable cgroup v2 memory-limit detection through libuv in version 20.3.0; the Node.js 18 line may see host memory instead of the Pod limit. That can inflate heap sizing and lead to out-of-memory terminations. Where an immediate runtime upgrade is impossible, explicitly sizing the heap can reduce risk while the application team completes its migration.
Go services that rely on automaxprocs should use version 1.5.1 or later. Similar checks apply to in-house utilities and scripts that parse v1 filenames such as cpu.shares or memory.limit_in_bytes. Under v2, operators will encounter interfaces such as cpu.weight, cpu.max and memory.max. Searching source repositories and container images for hard-coded cgroup paths can reveal dependencies that an infrastructure inventory misses.
Use a replacement node pool, not an in-place gamble
The most controlled migration pattern is to build a new, immutable node image with cgroup v2 enabled and introduce it as a separate node pool. That keeps the old pool available for rollback and makes scheduling an explicit test boundary. Label and taint the new pool, then move representative workloads onto it in stages.
Begin with stateless services that have meaningful CPU and memory behavior, followed by node-level agents and then stateful or latency-sensitive applications. For each stage, compare eviction rates, out-of-memory events, CPU throttling, startup latency and application-level service indicators with the v1 pool. Validate both ordinary load and resource pressure; compatibility problems often appear only when the kernel begins reclaiming memory or enforcing limits.
The migration should also include a direct enforcement check. Compare the requests and limits in the Pod specification with the resources recorded in container status, then inspect the runtime configuration and the relevant cgroup files on the node. This is especially important for in-place resource resizing, where desired and enacted values can briefly differ. A successful API update does not by itself prove that the kernel received the intended constraint.
Drain and replace nodes rather than changing the cgroup hierarchy underneath running workloads. The hierarchy is a boot-time host characteristic, and changing it in place combines an OS transition, kubelet restart and workload rescheduling into one difficult rollback. A new pool makes each step observable and lets operators halt the rollout without reconstructing the prior host state.
Expect behavior changes, not just compatibility fixes
cgroup v2 is not merely a renamed interface. It provides a unified hierarchy and enables Kubernetes features that cannot be implemented correctly on v1. Pressure Stall Information can expose CPU, memory and I/O contention at node, Pod and container scope when the kernel supports it. Container-aware out-of-memory handling can kill all processes in a container together, reducing the chance that a multi-process container remains partially alive after an OOM event.
CPU priority behavior can also shift. cgroup v1 uses cpu.shares, while v2 uses cpu.weight. Newer OCI runtimes, including runc 1.3.2 and crun 1.23, use an improved nonlinear conversion that gives small CPU requests better granularity. Any policy or monitoring system that predicts exact weight values may need adjustment after the runtime upgrade, even if the Kubernetes resource request is unchanged.
Memory QoS is another reason to complete the migration, but it should not be enabled casually. In Kubernetes 1.36 it remains alpha. On cgroup v2, memory.high can throttle Burstable containers, while an optional tiered reservation policy maps Guaranteed workloads to memory.min and Burstable requests to memory.low. Those controls promise more deliberate protection under pressure, but hard reservations consume real capacity. Teams should test them separately after the base cgroup migration rather than bundling two behavioral changes into one rollout.
A practical exit plan
Platform teams can keep the project bounded by treating cgroup v1 retirement as a node-platform release with explicit entry and exit criteria:
- Discover: report the cgroup version, kernel, OS image, runtime and driver for every Linux node.
- Audit: identify agents and applications that read the cgroup filesystem or infer memory and CPU capacity.
- Build: create a v2-first node image on a supported kernel and runtime, with kubelet and runtime drivers aligned.
- Canary: move representative workloads to a dedicated pool and test pressure, eviction, OOM and observability behavior.
- Replace: roll through node pools by draining and reprovisioning, with rollback capacity retained until service indicators stabilize.
- Remove exceptions: delete any
failCgroupV1: falseoverride and enforce a policy that prevents legacy images from re-entering the fleet.
The final step matters because an override can become invisible technical debt. If a cluster still depends on it, record the owner, affected pools and expiration release. Treat Kubernetes 1.38 as a hard boundary, not the date to begin investigation.
The upgrade is really a platform test
Kubernetes’ default failure on cgroup v1 nodes is intentionally disruptive: it makes an obsolete host assumption visible before workloads land on an unsupported foundation. The immediate task is to keep kubelets starting, but the larger opportunity is to verify that resource intent survives every layer between a Pod specification and the Linux kernel.
Teams that reduce the work to flipping failCgroupV1 will preserve short-term availability while carrying the same risk forward. Teams that use the deadline to modernize node images, runtimes, agents and workload assumptions will reach Kubernetes 1.38 with fewer exceptions—and with access to the resource-management capabilities that Kubernetes is building on cgroup v2.

