内核开启 cgroup v2:检测方法、开启步骤,以及 CentOS 7 为什么不支持
近期 Kubernetes 官方已正式弃用 cgroup v1(v1.35 起,kubelet 默认不再在 cgroup v1 节点上启动),节点启用 cgroup v2 正在从"可选项"变成"必答题"。本文整理:如何用一条命令确认系统用的是 v1 还是 v2、在支持的发行版上如何开启、Kubernetes 对 cgroup v2 的完整要求,以及一个高频疑问——CentOS 7 到底支不支持 cgroup v2。
一、cgroup v1 与 cgroup v2
cgroup(control group,控制组)是 Linux 内核用于约束、统计进程组资源(CPU、内存、IO 等)的机制,kubelet 和容器运行时正是通过它来落实 Pod 的 CPU/内存 requests 与 limits。
两个版本的核心差异:
| cgroup v1 | cgroup v2 | |
|---|---|---|
| 层级结构 | 每个控制器(cpu、memory、blkio……)各挂一棵独立的层级树,目录分散 | 单一统一层级,统一挂在 /sys/fs/cgroup |
| 资源核算 | 各控制器独立统计,内存/内核内存分开记账 | 统一核算(含网络内存、内核内存、页面缓存回写) |
| 子树委派 | 粒度粗,安全边界弱 | 支持更安全的子树委派给容器 |
| 新特性 | 冻结不再新增 | 支持 PSI(压力阻塞信息)等新原语,K8s 的 MemoryQoS 等特性依赖它 |
一句话:v2 是下一代的 cgroup API,Kubernetes 自 v1.25 起 cgroup v2 支持已是 GA。
二、一条命令确认当前是 v1 还是 v2
在节点上执行:
stat -fc %T /sys/fs/cgroup/
判定标准(来自 Kubernetes 官方文档):
- 输出
cgroup2fs→ 当前使用 cgroup v2 - 输出
tmpfs→ 当前使用 cgroup v1
辅助交叉验证:
# v1:/sys/fs/cgroup 下是一堆控制器目录(cpu、memory、blkio、pids...)
# v2:根目录下只有 cgroup.controllers、cgroup.subtree_control 等统一接口文件
ls /sys/fs/cgroup/
# v2 特有文件存在即为 v2
ls /sys/fs/cgroup/cgroup.controllers
# 看挂载方式
mount | grep cgroup
三、在受支持的发行版上开启 cgroup v2
1. 优先选默认启用 v2 的发行版
以下发行版默认启用 cgroup v2(K8s 官方列表):
- Container-Optimized OS(M97 起)
- Ubuntu(21.10 起,推荐 22.04+)
- Debian GNU/Linux(11 Bullseye 起)
- Fedora(31 起)
- Arch Linux(2021.04 起)
- RHEL 及类 RHEL 发行版(9 起)
2. 手动开启(以 RHEL/Rocky/Alma 8 为例)
RHEL 8 内核 4.18 支持 cgroup v2,但默认仍以 v1 方式挂载,需改内核启动参数。
方法一:grubby(RHEL 系推荐,改完立即写入所有内核条目,无需手改配置文件)
# 给所有已安装内核的启动参数追加 unified hierarchy 开关
grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"
# 确认参数已写入(查看默认内核的启动参数)
grubby --info=DEFAULT | grep args
方法二:改 GRUB 配置(通用写法)
# 编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 行末追加:
# systemd.unified_cgroup_hierarchy=1
# 重新生成 grub 配置(BIOS 与 UEFI 路径不同,二选一)
grub2-mkconfig -o /boot/grub2/grub.cfg # BIOS
grub2-mkconfig -o /etc/grub2-efi.cfg # UEFI
# Debian/Ubuntu 系直接:
sudo update-grub
生效与验证:
# 重启生效
reboot
# 验证
stat -fc %T /sys/fs/cgroup/ # 期望输出:cgroup2fs
说明:systemd.unified_cgroup_hierarchy=1 由 systemd 负责解析(systemd v239 起支持),它决定把 cgroup 层级以 v2(unified)方式挂载;如果 systemd 太老不认识这个参数,加了也白加——这正是后面 CentOS 7 的死结之一。
四、Kubernetes 使用 cgroup v2 的要求
| 组件 | 要求 |
|---|---|
| 内核 | 5.8 及以上 |
| containerd | v1.4 及更高 |
| cri-o | v1.20 及更高 |
| CGroup 驱动 | kubelet 与容器运行时统一使用 systemd cgroup 驱动 |
几个实用结论:
- kubelet 会自动检测节点跑在 v1 还是 v2 上,并自动调整行为,无需额外配置。
- 切换 v2 后日常使用没有感知差异,但直接读 cgroup 文件系统的组件要跟着升级:
- 第三方监控/安全代理:升级到支持 v2 的版本
- 独立部署的 cAdvisor:v0.43.0+
- Java:OpenJDK jdk8u372 / 11.0.16 / 15 及更高(IBM Semeru 8.0.382.0 / 11.0.20.0 / 17.0.8.0+)
- Node.js:v20.3.0 起才能可靠读取 v2 内存限制(v18 线不可靠,可能误读宿主机总内存导致 OOM,需显式
--max-old-space-size) - uber-go/automaxprocs:v1.5.1+
- cgroup v1 已弃用(K8s v1.35 起):默认 kubelet 不再在 v1 节点启动;确需过渡,要在 kubelet 配置文件中设置
failCgroupV1: false。迁移窗口不多,存量 v1 节点建议尽早规划。
五、重点:CentOS 7 是不是不支持 cgroup v2?
结论:不支持,而且是双重不支持,没有变通。
1. 内核层面:3.10 没有 cgroup v2
cgroup v2(unified hierarchy)在内核 3.16 才首次合入(实验性),4.5 起才稳定。CentOS 7 的内核是 3.10——比 v2 首次合入还要老 6 个小版本,内核代码里根本没有 cgroup2 这套东西。
所以在 CentOS 7 上:
$ stat -fc %T /sys/fs/cgroup/
tmpfs # 永远是 tmpfs,即 v1
# 就算把参数塞进 grub,内核 3.10 只会当成 unknown parameter 无视掉
# systemd.unified_cgroup_hierarchy=1
2. systemd 层面:219 也不支持 v2
cgroup v2 的挂载切换由 systemd 完成,这要求较新的 systemd。CentOS 7 的 systemd 是 219(2015 年的版本),完全不支持 unified hierarchy 模式,也不认识 systemd.unified_cgroup_hierarchy 参数。
这意味着:即使通过 ELRepo 把内核升级到 5.x(内核本身已支持 cgroup2),systemd 219 依然无法以 v2 方式挂载和管理 cgroup 层级。强行用内核参数 cgroup_no_v1=all 禁用 v1 去逼系统走 v2,只会让 systemd 的服务资源管理失效,得不偿失。另外别忘了,K8s 官方对 v2 的内核要求是 5.8+,el7 仓库归档前的最终内核 5.4.278 也够不着这条线。
3. 汇总对照
| 系统 | 内核 | systemd | cgroup v2 |
|---|---|---|---|
| CentOS 7 | 3.10 | 219 | 完全不支持(内核、systemd 双重缺失) |
| RHEL/Rocky/Alma 8 | 4.18 | 239 | 支持但默认关闭,可手动开启(见第三节) |
| RHEL/Rocky/Alma 9 | 5.14 | 249 | 默认开启 |
| Ubuntu 22.04 | 5.15+ | 249 | 默认开启 |
4. 实际路径建议
想用 cgroup v2,CentOS 7 上没有升级项可打,只有一条路:换系统。结合 K8s 要求(内核 5.8+、systemd cgroup 驱动),推荐:
- RHEL 9 / Rocky Linux 9 / AlmaLinux 9(内核 5.14,开箱即 v2,且是 RHEL 系平滑迁移路径)
- Ubuntu 22.04 LTS、Debian 12
CentOS 7 本身已于 2024-06-30 EOL,与其在旧系统上反复打补丁,不如把"换发行版 + 启用 cgroup v2 + 重装 K8s 节点"作为一个整体迁移项目来做。内核升级的思路可以参考之前写的 CentOS 7.9 升级内核至 5.4.278 实战记录——但请明确:那解决的是内核新特性需求,解决不了 cgroup v2 的问题。
六、小结
- 判断版本只要一条命令:
stat -fc %T /sys/fs/cgroup/,cgroup2fs是 v2,tmpfs是 v1。 - 开启 v2 首选默认启用的发行版(RHEL 9+、Ubuntu 22.04+ 等);RHEL 8 系推荐
grubby --update-kernel=ALL --args="systemd.unified_cgroup_hierarchy=1"一条命令开启(或改 GRUB 配置)。 - K8s 侧要求:内核 5.8+、containerd 1.4+、systemd cgroup 驱动;v1 已弃用,kubelet 默认不再在 v1 节点启动。
- CentOS 7 = 内核 3.10 + systemd 219,两头都不支持 cgroup v2,升级内核也无解,只能换系统。
参考:
- Kubernetes 官方文档《关于 CGroup v2》:https://kubernetes.io/zh-cn/docs/concepts/architecture/cgroups/
- runc cgroup v2 文档(发行版支持列表):https://github.com/opencontainers/runc/blob/main/docs/cgroup-v2.md
- cgroup 手册页:https://man7.org/linux/man-pages/man7/cgroups.7.html