US Edition Austin, TX UTC 00:00:00

How to check cgroup version on Linux before upgrading to Kubernetes 1.35

Run stat -fc %T /sys/fs/cgroup/: cgroup2fs means v2, tmpfs means v1. Why it matters now that Kubernetes 1.35+ kubelets won't start on cgroup v1.

To check which cgroup version a Linux machine uses, run stat -fc %T /sys/fs/cgroup/. If it prints cgroup2fs, the host runs cgroup v2; tmpfs means cgroup v1 or the older hybrid layout, which Kubernetes also treats as v1. The check matters because since Kubernetes 1.35 the kubelet refuses to start on cgroup v1 nodes by default, and as of October 2026 that applies to every release the project still maintains.

Kubernetes 1.34 reached end of life on October 27, 2026, leaving 1.35, 1.36 and 1.37 as the maintained versions on the official releases page. Our Kubernetes 1.34 end-of-life guide covers the EKS, GKE and AKS deadlines.

How to check the cgroup version on a Linux host

The Kubernetes documentation uses the stat check above; other commands confirm it:

  • stat -fc %T /sys/fs/cgroup/ prints the type of filesystem mounted at the cgroup root: cgroup2fs for v2, tmpfs for v1.
  • ls /sys/fs/cgroup/cgroup.controllers succeeds only on v2. Docker's runtime metrics documentation uses this file as its test.
  • mount | grep cgroup on a v2 host shows a single cgroup2 filesystem mounted on /sys/fs/cgroup, the result Red Hat documents after enabling v2. A v1 host shows a tmpfs at /sys/fs/cgroup and a separate cgroup mount for each controller, such as /sys/fs/cgroup/memory.
  • docker info | grep -i cgroup prints the Cgroup Version and Cgroup Driver lines on Docker Engine hosts, and podman info | grep -i cgroupversion does the same for Podman.

Hybrid mode counts as v1

Some older systemd-based distributions boot a hybrid layout: v1 controllers under a tmpfs at /sys/fs/cgroup, plus a v2 tree at /sys/fs/cgroup/unified. The kubelet relies on the opencontainers/cgroups library, which counts a host as v2 only when /sys/fs/cgroup itself is a cgroup2 filesystem. A cgroup2 line elsewhere in the mount list is not enough.

How to check every node in a Kubernetes cluster

Logging in to each node does not scale, and on managed services it may not be possible. Two checks work from kubectl:

  • kubectl get nodes -o wide lists each node's OS image and kernel version. Older distributions and kernels below 5.8, the minimum the Kubernetes docs set for cgroup v2, are the first suspects.
  • kubectl debug node/<node> -it --image=ubuntu -- stat -fc %T /sys/fs/cgroup/ runs the stat check in a node debugging pod. The runtime gives the pod a cgroup mount of the node's version, so the result matches the host; delete the node-debugger pod afterwards.

Kubelets from 1.31 onward also publish an alpha gauge, kubelet_cgroup_version, set to 1 or 2. If your account may use the nodes/proxy subresource, read it with kubectl get --raw "/api/v1/nodes/<node>/proxy/metrics" | grep kubelet_cgroup_version. To check every node of a 1.34 or older cluster before upgrading:

for n in $(kubectl get nodes -o name); do echo "$n $(kubectl get --raw /api/v1/nodes/${n#node/}/proxy/metrics | grep '^kubelet_cgroup_version')"; done

Managed services have moved their default node images to v2, but older node pools can still run v1:

  • GKE has used cgroup v2 by default for new nodes since 1.26, began migrating v1 clusters in 1.33 and removes v1 support in 1.35, per Google's migration guide. Look for node pools explicitly set to v1.
  • EKS stopped publishing Amazon Linux 2 AMIs, which run cgroup v1, on November 26, 2025; 1.32 was the last version to get them, per the EKS AL2 transition FAQ. AL2023 and Bottlerocket run v2, so custom AL2-based images are the risk.

What Kubernetes 1.35 and later do on a cgroup v1 node

The Kubernetes 1.35 release announcement of December 17, 2025 called it the removal of cgroup v1 support. The mechanism is the kubelet setting failCgroupV1, whose default became true, as the project's October 2026 post on cgroup v2 explains. In practice:

  • The kubelet stops during configuration validation with the error "kubelet is configured to not run on a host using cgroup v1", as defined in the kubelet source. A new node never registers, and an existing node goes NotReady once its kubelet is upgraded.
  • On kubeadm clusters, the SystemVerification preflight check fails kubeadm init, join and upgrade when it finds cgroup v1 alongside a 1.35 or newer kubelet.
  • Setting failCgroupV1: false in the kubelet configuration file lets the kubelet start. On kubeadm nodes that file is /var/lib/kubelet/config.yaml; kubeadm join writes it from the kubelet-config ConfigMap in kube-system, so change the ConfigMap too.
  • A kubelet running with the override records a Warning event with the reason CgroupV1 on its Node object.

The override is a stopgap. KEP-5573 commits to deleting the cgroup v1 code and says removal will come no earlier than 1.38. As of October 2026, the 1.35, 1.36 and 1.37 kubelets still accept failCgroupV1: false.

1.35 is also the last release that supports containerd 1.x, so nodes need containerd 2.0 or later before the next upgrade; the kubelet_cri_losing_support metric flags the ones that do not.

Which Linux distributions use cgroup v2 by default

The Kubernetes docs recommend running a distribution that enables cgroup v2 by default. Based on the Kubernetes list and vendor documentation:

  • cgroup v2 by default: Ubuntu 21.10 and later (22.04 or later recommended), Debian 11 and later, Fedora 31 and later, RHEL and RHEL-like distributions from version 9, Arch Linux since April 2021, Container-Optimized OS since M97, Amazon Linux 2023 and Bottlerocket.
  • cgroup v1 by default: RHEL 8, Amazon Linux 2, Ubuntu releases before 21.10 and Debian releases before 11.

Operating systems are dropping v1 as well. systemd 256 treats v1 as obsolete and refuses to boot under it unless SYSTEMD_CGROUP_ENABLE_LEGACY_FORCE=1 is on the kernel command line, and systemd 258 removed v1 support entirely. Red Hat's RHEL 9.4 release notes say systemd in RHEL 10 will not boot in v1 mode, and AWS calls v1 on AL2023 an unsupported configuration.

How to switch a node to cgroup v2

The cleanest route, and the one the Kubernetes docs recommend, is to replace v1 nodes with new ones built from an image that boots v2 by default. The container runtime documentation also warns that changing the cgroup driver on an already joined node can break existing pod sandboxes. If you must convert a node in place:

  1. Check the kernel with uname -r. Kubernetes lists 5.8 as the minimum for cgroup v2; on an older kernel, move to a newer OS release instead.
  2. Drain the node: kubectl drain <node> --ignore-daemonsets --delete-emptydir-data.
  3. Add systemd.unified_cgroup_hierarchy=1 to the kernel command line. Red Hat's procedure is sudo grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"; on GRUB systems such as Ubuntu and Debian, add it to GRUB_CMDLINE_LINUX in /etc/default/grub and run sudo update-grub. If cat /proc/cmdline shows systemd.unified_cgroup_hierarchy=0, remove it, because that value forces v1.
  4. Use the systemd cgroup driver, which the Kubernetes docs recommend with v2: set SystemdCgroup = true in containerd's runc options (plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options in 1.x, plugins.'io.containerd.cri.v1.runtime'.containerd.runtimes.runc.options in 2.x) and cgroupDriver: systemd for the kubelet. With containerd 2.0 or CRI-O 1.28 and later, the kubelet reads the driver from the runtime.
  5. Reboot, confirm that stat prints cgroup2fs, then run kubectl uncordon <node>.

Workloads that notice the switch

According to the Kubernetes migration notes, the kubelet adapts to v2 on its own and most workloads see no difference. The exceptions are programs that read the cgroup filesystem directly, with these minimum versions:

  • Java: OpenJDK/HotSpot jdk8u372, 11.0.16, or 15 and later; IBM Semeru Runtimes 8.0.382.0, 11.0.20.0, 17.0.8.0 and later; IBM Java 8.0.8.6 and later. AWS notes that JDK 8 builds older than jdk8u372 size the heap from node memory instead of the pod limit, which leads to OOM kills and restarts.
  • Node.js: 20.3.0 or later reads v2 memory limits through libuv; the 18 line does not detect them reliably. On older versions, set the heap size with --max-old-space-size.
  • Go: uber-go/automaxprocs 1.5.1 or later.
  • Monitoring: a standalone cAdvisor DaemonSet needs v0.43.0 or later, and third-party monitoring and security agents need releases that support v2.

In-house scripts that read v1 files need new paths. Per the kernel's cgroup v2 documentation, the common replacements are:

  • memory.limit_in_bytes becomes memory.max
  • memory.usage_in_bytes becomes memory.current
  • cpu.cfs_quota_us and cpu.cfs_period_us become a single cpu.max file in the format "$MAX $PERIOD"
  • cpu.shares gives way to cpu.weight, which uses a different scale

Out-of-memory handling changes too. On v2 nodes the kubelet sets memory.oom.group on each container, so an OOM kill ends every process in that container instead of one; singleProcessOOMKill: true in the kubelet configuration restores the v1-style behavior. A container stopped this way reports exit code 137, covered in our container exit codes guide. Related coverage is in our Platforms and Infrastructure sections.

Frequently asked questions

How do I check if cgroup v2 is enabled?

Run stat -fc %T /sys/fs/cgroup/. If it prints cgroup2fs, cgroup v2 is mounted at the cgroup root and in use; tmpfs means the host runs cgroup v1 or the hybrid layout.

Does Kubernetes 1.35 remove cgroup v1 support?

Kubernetes 1.35 deprecated cgroup v1 and changed failCgroupV1 to true by default, so the kubelet will not start on a v1 node unless an administrator sets failCgroupV1: false. The code itself is still there; KEP-5573 puts its removal no earlier than 1.38.

Why does the kubelet fail to start after upgrading to 1.35?

If the kubelet log says it is configured to not run on a host using cgroup v1, the node boots with cgroup v1 or the hybrid layout. Move the node to cgroup v2, or set failCgroupV1: false in the kubelet configuration while you migrate.

How do I enable cgroup v2 on Linux?

Add systemd.unified_cgroup_hierarchy=1 to the kernel command line, with grubby on RHEL-family systems or GRUB_CMDLINE_LINUX plus update-grub on Debian and Ubuntu, then reboot. For Kubernetes nodes the kernel should be 5.8 or newer, and moving to a distribution that boots v2 by default is the recommended path.

Which Kubernetes versions still start on cgroup v1 by default?

Kubernetes 1.34 and earlier start on cgroup v1 nodes without changes, but 1.34 reached end of life on October 27, 2026. As of October 2026, 1.35, 1.36 and 1.37 need failCgroupV1: false to run on a v1 node.