这是典型的 cgroup 驱动不匹配问题:宿主机用 systemd 管理 cgroups,但 kubelet 配置为 cgroupfs,导致无法获取根 cgroup 统计,进而使资源限制、oom 判定等功能失效。

为什么 kubelet 启动失败并报 “failed to run Kubelet: failed to get root cgroup stats”?
这是典型的 cgroup 驱动不匹配问题:宿主机用 systemd 管理 cgroups(现代主流发行版默认),但 kubelet 却配置成 cgroupfs,导致它找不到正确的 cgroup 根路径,连带容器运行时(如 containerd)的统计、OOM 判定、CPU/内存限制全部失效。
- 检查当前系统实际使用的 cgroup 版本:
stat -fc %T /sys/fs/cgroup—— 若输出cgroup2fs,说明是 cgroup v2 + systemd;若为cgroupfs且目录下有systemd子目录,大概率是 cgroup v1 + systemd 混合模式 -
kubelet的--cgroup-driver必须和containerd的config.toml中[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options]下的SystemdCgroup = true/false严格一致 - 常见错误:只改
kubelet参数,忘了同步改containerd配置,结果 kubelet 起来了,但 Pod 一直卡在ContainerCreating
如何安全地把已运行集群从 cgroupfs 迁移到 systemd?
不能直接改参数重启,否则所有 Pod 的 cgroup 路径会断开,资源限制立即失效,可能触发批量 OOM 或 CPU 抢占异常。
- 先确认 containerd 已启用 systemd cgroup:编辑
/etc/containerd/config.toml,确保SystemdCgroup = true,然后执行sudo systemctl restart containerd - 再更新 kubelet:修改
/var/lib/kubelet/kubeadm-flags.env(或 systemd unit 文件中的Environment="KUBELET_EXTRA_ARGS=..."),加入--cgroup-driver=systemd - 必须滚动重启节点:逐台 drain → 停 kubelet → 清空
/var/lib/kubelet/cgroup(如有)→ 启 kubelet → 等 Ready → uncordon。跳过清空步骤可能导致旧 cgroup 目录残留,kubelet 统计错乱
systemd cgroup driver 在 cgroup v2 下有哪些实际差异?
cgroup v2 是单层树、统一接口,而 systemd 驱动在 v2 下不再依赖 /sys/fs/cgroup/<controller>/kubepods/...</controller> 这类传统路径,而是通过 systemd unit 名称(如 kubepods-burstable-podxxx.slice)组织层级,这对监控和调试带来变化。
-
crictl stats和kubectl top pod仍可用,但底层数据来自 systemd 的dbus接口或/sys/fs/cgroup/cgroup.procs,不是传统文件读取 - 手动 inspect cgroup:用
systemctl status <unit-name></unit-name>查资源使用,或cat /sys/fs/cgroup/<unit-name>/cpu.max</unit-name>(v2)代替旧版cpu.cfs_quota_us - 某些老版本监控 agent(如早期 cadvisor)对 v2 + systemd 支持不完整,可能显示 0 值或 panic,需升级到 v0.47+
哪些场景下硬切 systemd 会出意料之外的问题?
不是所有环境都适合一刀切。尤其当节点混用多种运行时(比如同时跑 docker、podman、containerd),或使用自定义 cgroup 路径时,systemd 驱动可能绕过你预设的隔离逻辑。
- Docker 用户注意:Docker CE 24.0+ 默认用
systemdcgroup,但若你还在用dockerd --exec-opt native.cgroupdriver=cgroupfs,和 kubelet 的systemd驱动共存会导致 cgroup 层级冲突 - 内核参数未调优:cgroup v2 + systemd 要求
systemd.unified_cgroup_hierarchy=1,若 BIOS/UEFI 启用了 legacy cgroup,该参数会被忽略,kubelet会静默回退到 cgroup v1 行为,但日志不报错 - SElinux 强制模式下,systemd 创建的 cgroup slice 可能被策略拒绝写入,表现为 Pod 启动超时,需检查
ausearch -m avc -ts recent
迁移的核心不是改一个参数,而是确认整个 cgroup 生命周期——从内核挂载、systemd 初始化、containerd 创建 runtime、到 kubelet 分配 pod scope——全部落在同一套语义里。少一环,就可能在半夜收到 CPU 使用率突增告警,却查不到是哪个 Pod 在啃资源。