Kubernetes 集群迁移到 Cgroup V2:原理、兼容性验证与启用步骤
Cgroup V2 相较于 V1 提供了统一层级、更完善的 IO QoS 支持,尤其是对 Buffer IO 的限速能力,是 Kubernetes 集群提升资源利用率的重要基础。本文记录在生产 Kubernetes 集群上迁移到 Cgroup V2 的完整过程:依赖版本要求、启用步骤,以及 CPU、内存、PID、IO 等各资源控制器的兼容性验证结果。
为什么迁移到 Cgroup V2
Cgroup V1 的问题
Cgroup V1 允许多个独立的层级同时存在(每个 controller 一个层级),导致:
- 同一进程在多个层级中有不同的位置,管理复杂
- Controller 之间行为不一致,难以推理
- 资源统计存在重复计算
Cgroup V2 的改进
V2 将所有 controller 合并到单一统一层级(unified hierarchy):
1 | /sys/fs/cgroup/ |
核心优势:
- 统一层级:所有 controller 在同一目录树下,管理简单
- Buffer IO 限速:V1 只能限制 Direct IO,V2 通过
io.max实现对 Buffer IO 的限速 - IO 权重调度:配合 BFQ/CFQ 调度器实现
io.weight按比例分配 IO 带宽 - iocost 模型:基于延迟的 IO 代价模型,实现更智能的 QoS 调控
依赖版本要求
| 组件 | 最低版本 | 推荐版本 | 说明 |
|---|---|---|---|
| Linux Kernel | 4.15 | 5.2+ | 5.6+ 才支持 hugetlb controller |
| Kubernetes | 1.19 | 1.25+ | 1.19 起正式支持 Cgroup V2 |
| containerd | 1.4.4 | 1.6+ | 需支持 unified cgroup hierarchy |
| runc | v1.0.0-rc91 | v1.0.0+ | rc93 起全面支持 unified mode |
| systemd | 244 | 249+ | 244 起支持 cpuset controller delegation |
| cAdvisor | v0.36.1 | v0.45+ | 支持 cgroup v2 指标采集 |
启用步骤
1. 升级内核
推荐使用 5.4 或 5.15 内核。低于 4.15 的内核不支持 Cgroup V2。
2. 升级 containerd
containerd 1.4.4 起支持 cgroup v2 unified mode。升级后无需额外配置,containerd 会自动检测宿主机的 cgroup 版本。
3. 添加内核启动参数
在 GRUB 或内核命令行中添加:
1 | cgroup_no_v1=all |
可选参数(用于 IO 调试和优化):
1 | blk_cgroup.blkcg_debug_stats=1 # 开启 blkcg 调试统计 |
重启后验证:
1 | # 确认已切换到 cgroup v2 |
4. 加载 BFQ 调度器模块
IO 权重调度依赖 BFQ 调度器:
1 | modprobe bfq |
5. 升级 Kubernetes(或 cherry-pick)
Kubernetes 1.19 起原生支持 Cgroup V2,主要相关 commit:
bb5ed1b7:kubelet 初始 cgroupv2 支持a9772b22:CPU hard cap 在 cgroupv2 上的实现79be8be1:hugetlb cgroup 设为可选(兼容低版本内核)26d94ad6:device cgroup 在 v2 模式下不配置
对于低版本 Kubernetes,可以 cherry-pick 上述 commit。
兼容性验证
以下基于实际测试环境(kernel 5.4,Kubernetes 1.23,containerd 1.4.4)的验证结果。
CPU 控制器
Cgroup V2 使用 cpu.max 替代 V1 的 cpu.cfs_quota_us + cpu.cfs_period_us:
1 | # Pod 级别(Pod 总 CPU limit) |
行为与 V1 一致,对应用无感知差异。
内存控制器
memory.max 替代 V1 的 memory.limit_in_bytes:
1 | # Pod 总内存 limit |
注意:V2 新增了
memory.min(硬保证)、memory.low(软保证)、memory.high(压制阈值)等接口,Kubernetes 目前未使用这些字段(值为 0 或 max)。上游 KEP(#2571)正在推进 Memory QoS 支持。
PID 控制器
pids.max 替代 V1 的 pids.limit:
1 | cat /var/lib/kubelet/config.yaml | grep podPidsLimit |
行为完全一致。
Hugetlb 控制器
内核 5.4 不支持 hugetlb 加入 cgroupv2 controller,需要内核 5.6+。
这是从 V1 迁移到 V2 时最主要的兼容性限制点。如果业务 Pod 使用了 HugePages 资源限制,需要确认内核版本满足要求,或在迁移前评估影响。
IO 控制器(核心新功能)
Cgroup V2 IO 接口:
| 接口 | 作用 |
|---|---|
io.max |
限制最大带宽(BPS)或 IOPS,支持 Direct IO 和 Buffer IO |
io.weight |
按权重比例分配 IO 带宽(需 BFQ/CFQ 调度器) |
io.stat |
IO 统计信息 |
io.cost.qos |
基于延迟的代价模型 QoS 配置 |
io.cost.model |
iocost 的物理参数建模 |
启用示例:
1 | # 对设备 8:0 启用 iocost |
V2 IO 控制器相较 V1 最重要的突破是对 Buffer IO 的支持。V1 只能通过 blkio.throttle.write_bps_device 限制 Direct IO,Buffer IO 完全不受控制。V2 通过跟踪 page cache 的 writeback 来实现对 Buffer IO 的限速,这对于实际生产中以 Buffer IO 为主的工作负载(如数据库、日志服务)意义重大。
迁移注意事项
- 滚动升级:内核参数变更需要重启节点,建议通过节点轮转(cordon + drain + reboot)的方式平滑迁移
- Hugetlb 兼容性:使用 HugePages 的工作负载需要内核 5.6+,迁移前评估
- BFQ 模块:IO 权重功能依赖 BFQ 模块,需要在启动脚本中持久化
modprobe bfq - iocost 稳定性:
io.cost.qos的自动权重调整(ctrl=auto)在高并发 IO 场景下可能导致 CPU 软锁,建议先在测试环境充分验证,生产使用时优先考虑ctrl=user模式