Skip to main content
DevOps Insightsguides & answers

Kubernetes · troubleshooting

kubelet is configured to not run on a host using cgroup v1

From Kubernetes 1.35 the kubelet refuses to start on a node that still uses cgroup v1, because its failCgroupV1 setting now defaults to true. The lasting fix is moving the node to cgroup v2. To buy time, set failCgroupV1: false; with kubeadm, also add it to the kubelet-config ConfigMap before upgrading and skip the SystemVerification preflight check.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 10 sections

Before you start

  • Shell access to the node: the kubelet's own log, the cgroup filesystem and the kernel command line are only visible there.
  • Permission to edit the kubelet configuration (and, with kubeadm, the kube-system/kubelet-config ConfigMap).
  • A maintenance window if the fix is moving the node to cgroup v2: that means a kernel or distribution change and a reboot.

Run this first

step 1 of 3
sudo journalctl -u kubelet --since "-15min" | grep -i cgroup

Look for kubelet is configured to not run on a host using cgroup v1

The kubelet logs the reason before it exits, then systemd restarts it and the line repeats.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

What does stat -fc %T /sys/fs/cgroup/ print on the node?

Cause space

2 of 2 still possible

  • The node's operating system still runs cgroup v1Common
  • A kubeadm upgrade reached 1.35 without the documented overrideOccasional

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Check it with a tool

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    sudo journalctl -u kubelet --since "-15min" | grep -i cgroup

    The kubelet logs the reason before it exits, then systemd restarts it and the line repeats.

    Look for kubelet is configured to not run on a host using cgroup v1

  2. Step 2

    stat -fc %T /sys/fs/cgroup/

    The documented way to tell which cgroup version the node runs.

    Look for tmpfs (v1) or cgroup2fs (v2)

  3. Step 3

    sudo grep -n -i cgroup /var/lib/kubelet/config.yaml

    Shows whether failCgroupV1 is set and which cgroupDriver the kubelet uses; v2 needs the systemd driver.

    Look for failCgroupV1 and cgroupDriver: systemd

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

The node's operating system still runs cgroup v1

Common

The kubelet checks the host's cgroup mode, and with failCgroupV1 true (the default from 1.35) it refuses a v1 host. Distributions older than the ones that switched to v2 by default, or nodes booted with cgroup v2 turned off, are in this state.

Confirm

stat -fc %T /sys/fs/cgroup/
cat /proc/cmdline

tmpfs means cgroup v1; cgroup2fs means v2. The kernel command line shows whether systemd.unified_cgroup_hierarchy is being set

Fix

  • Move the node to cgroup v2. The documentation recommends a distribution that enables it by default; on GRUB-based systems it describes adding systemd.unified_cgroup_hierarchy=1 to GRUB_CMDLINE_LINUX in /etc/default/grub, running sudo update-grub and rebooting.
  • Check the v2 requirements first: kernel 5.8 or later, containerd 1.4+ or CRI-O 1.20+, and the systemd cgroup driver for both the kubelet and the runtime. The kubelet detects v2 by itself; no kubelet setting changes.
  • Drain the node first (kubectl drain <node> --ignore-daemonsets) and uncordon it once it is Ready on v2.

A kubeadm upgrade reached 1.35 without the documented override

Occasional

kubeadm writes the kubelet's configuration from the kube-system/kubelet-config ConfigMap. If the node must stay on cgroup v1 for now, the 1.35 changelog says to add failCgroupV1: false to that ConfigMap before upgrading and to ignore the SystemVerification error. Upgrading without both leaves either the preflight check or the kubelet refusing.

Confirm

kubectl -n kube-system get configmap kubelet-config -o yaml | grep -n failCgroupV1
sudo grep -n failCgroupV1 /var/lib/kubelet/config.yaml

No failCgroupV1: false in either place on a node that is still on cgroup v1

Fix

  • Add failCgroupV1: false to the kubelet configuration in the kube-system/kubelet-config ConfigMap, then run the upgrade with --ignore-preflight-errors=SystemVerification.
  • On a node already upgraded, add failCgroupV1: false to /var/lib/kubelet/config.yaml and restart the kubelet (sudo systemctl restart kubelet), so the next kubeadm run does not overwrite it from the ConfigMap.
  • Treat this as a bridge to cgroup v2, not a destination.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Linux uses control groups (cgroups) to limit how much CPU and memory each process gets, and Kubernetes relies on them to enforce your pods' requests and limits. There are two versions, and most current distributions use the newer one, cgroup v2. Since version 1.35 the kubelet, the Kubernetes agent on each node, stops at startup if the node still uses the old version, rather than run on a setup it no longer supports.

Words used on this page

cgroup (control group)
A Linux kernel feature that groups processes and limits the resources they can use. The kubelet and the container runtime use it to apply pods' CPU and memory requests and limits.
cgroup v1 and v2
The two versions of the cgroup interface. v2 has a single unified hierarchy. The Kubernetes documentation lists its requirements as kernel 5.8 or later, a runtime that supports it (containerd 1.4+, CRI-O 1.20+) and the systemd cgroup driver.
failCgroupV1
A kubelet configuration option. When true, the kubelet refuses to start on a cgroup v1 host. Its default became true in 1.35.
SystemVerification
A kubeadm preflight check run by kubeadm init, join and upgrade. From kubeadm 1.35 it fails, rather than warns, when it finds cgroup v1 with a 1.35 or newer kubelet.
What is actually happening

The kubelet validates its configuration at startup. In 1.35 its failCgroupV1 option began defaulting to true, so on a host whose cgroup filesystem is v1 the validation fails with the message above and the kubelet exits. Under systemd it then restarts and fails again, and the node goes NotReady.

It is a configured refusal, not a crash: the 1.37 release notes confirm that setting failCgroupV1: false still lets the kubelet run on cgroup v1. The 1.35 release called the change the removal of cgroup v1 support, and support is being removed in stages.

kubeadm reports the same thing earlier. From kubeadm 1.35 the SystemVerification preflight check fails with "cgroups v1 support is deprecated and will be removed in a future release…" when the kubelet version is 1.35 or newer, so kubeadm upgrade stops before touching the node.

Which version a node uses is decided by the distribution and the kernel command line, not by Kubernetes. The documentation lists Ubuntu 21.10+, Debian 11+, RHEL 9+, Fedora 31+ and Container-Optimized OS M97+ as enabling cgroup v2 by default, so long-lived nodes on older releases are the usual case.

How to tell this is your problem
WhereWhat you see
journalctl -u kubeletkubelet is configured to not run on a host using cgroup v1. cgroup v1 support is unsupported and will be removed in a future release
kubeadm upgrade, join or init (preflight)cgroups v1 support is deprecated and will be removed in a future release. Please migrate to cgroups v2. …
kubectl get nodesThe upgraded node is NotReady
stat -fc %T /sys/fs/cgroup/ on the nodetmpfs (cgroup v1), rather than cgroup2fs (cgroup v2)

How to know it is actually fixed

  • stat -fc %T /sys/fs/cgroup/ prints cgroup2fs after the migration.
  • sudo systemctl status kubelet shows active (running) and stays that way.
  • kubectl get node <node> shows Ready, and pods scheduled to it start.

Stopping it happening again

  • Before upgrading a cluster to 1.35, run stat -fc %T /sys/fs/cgroup/ on every node and list any that print tmpfs.
  • Build new nodes from a distribution release that uses cgroup v2 by default.
  • Read the release's Urgent Upgrade Notes before every minor upgrade; this change was marked ACTION REQUIRED there.

Security considerations

  • Turning failCgroupV1 off keeps a node on a configuration the project has deprecated and is removing; treat it as temporary and plan the migration.
  • Skipping a kubeadm preflight check skips only the check you name. Pass --ignore-preflight-errors=SystemVerification, not all, so other real problems still stop the upgrade.
  • Workloads that read the cgroup filesystem directly, such as some monitoring agents and older JVMs, can misreport limits after the switch to v2. Upgrade them before migrating the node.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it