Docker 隔离的底层秘密:cgroup 到底在干啥?

cgroup 详解

cgroup(Control Groups)是 Linux 内核提供的资源隔离与限制机制,用于对进程组(process groups)的 CPU、内存、IO、网络等系统资源进行精细化控制。它是容器技术(如 Docker、Kubernetes)、虚拟化、资源管理工具(如 systemd)的核心底层依赖,核心目标是:将进程分组管理,为每组分配可控的资源配额,避免单个进程/组过度占用资源影响系统稳定性

一、核心概念

理解 cgroup 需先掌握 4 个核心术语:

术语作用
任务(Task)即 Linux 进程(PID 对应的实体),是 cgroup 资源控制的最小单位,一个任务可加入多个 cgroup(不同子系统)。
控制组(cgroup)一组被统一资源控制的任务集合,可包含子 cgroup(形成层级结构,资源可继承/限制)。
子系统(Subsystem)即资源控制器(Resource Controller),对应一种具体资源的控制能力(如 CPU 子系统控制 CPU 使用率)。
层级(Hierarchy)由多个 cgroup 组成的树状结构(与文件系统目录树类似),一个层级绑定一个或多个子系统,任务通过挂载层级的目录加入 cgroup。

关键关系(核心规则)

  1. 一个层级可绑定 多个子系统(共同控制该层级下 cgroup 的资源);
  2. 一个子系统只能绑定 一个层级(避免资源控制冲突);
  3. 一个任务可加入 多个层级 的 cgroup(每个层级对应不同子系统,实现多资源控制);
  4. 同一层级中,一个任务 只能属于一个 cgroup(层级是树状结构,任务需明确归属某一分支)。

二、主要子系统(资源控制器)

Linux 内核支持的核心子系统(不同内核版本可能略有差异,lssubsys -a 可查看当前系统支持的子系统):

子系统名称功能描述
cpu限制 cgroup 中任务的 CPU 使用率(如限制最多使用 50% CPU)。
cpuacct统计 cgroup 中任务的 CPU 使用情况(如用户态/内核态 CPU 耗时、总使用率)。
memory限制 cgroup 的内存使用上限(物理内存+交换空间),并统计内存使用量。
blkio限制块设备 IO 带宽(如硬盘、SSD),控制读写速度、IO 优先级。
devices控制 cgroup 中任务对设备的访问权限(允许/禁止读写/创建某类设备,如 /dev/sda)。
net_cls为 cgroup 中的网络数据包打上类标识(classid),配合 tc 工具做网络限流。
net_prio控制 cgroup 中任务的网络流量优先级。
pid限制 cgroup 中允许创建的最大进程数(PID 数量)。
freezer暂停/恢复 cgroup 中的所有任务(类似 kill -STOP/CONT,用于容器暂停)。
cpuset绑定 cgroup 中任务到指定 CPU 核心和 NUMA 节点(如仅允许使用 CPU0/CPU1)。
hugetlb限制 cgroup 对大页内存(HugeTLB)的使用。
rdma限制 cgroup 对 RDMA(远程直接内存访问)资源的使用。

三、cgroup 的两种版本:v1 vs v2

cgroup 有两个主要版本,v2 是内核 4.5+ 引入的新一代架构,解决了 v1 的设计缺陷(如子系统分散、层级冲突),目前已成为 Docker、Kubernetes 的默认推荐版本。

核心差异对比

特性cgroup v1cgroup v2
子系统管理每个子系统独立层级,分散挂载(如 /sys/fs/cgroup/cpu所有子系统统一到一个层级,挂载点 /sys/fs/cgroup/unified(或直接 /sys/fs/cgroup
资源继承子 cgroup 需单独配置,无统一默认子 cgroup 自动继承父 cgroup 资源限制,配置更简洁
内存控制物理内存、交换空间分开限制(memory.limit_in_bytes统一限制(memory.max),支持 OOM 优先级
CPU 控制依赖 cpu.shares(相对权重)、cpu.cfs_quota_us(绝对限制)简化为 cpu.max(绝对限制)、cpu.weight(相对权重),支持 CPU 带宽控制
进程管理任务可属于多个层级的 cgroup任务仅属于一个 cgroup(统一层级),避免冲突
兼容性支持所有老工具(如 docker run --cpus 早期版本)需工具适配(Docker 19.03+、K8s 1.19+ 完全支持)

查看当前系统使用的版本

# 方法1:查看挂载点
mount | grep cgroup

# 若输出包含 /sys/fs/cgroup/unified 或 /sys/fs/cgroup 且无单独子系统挂载,即为 v2
# 若输出多个 /sys/fs/cgroup/cpu、/sys/fs/cgroup/memory 等,即为 v1

# 方法2:通过 /proc/cgroups 判断
cat /proc/cgroups
# v2 中所有子系统的 hierarchy 列值相同(统一层级),v1 中不同子系统值不同

四、cgroup 实操(v2 示例)

cgroup 基于文件系统实现,所有配置均通过操作 /sys/fs/cgroup 下的文件完成(需 root 权限)。以下以 “限制进程 CPU 使用率、内存上限” 为例,演示手动配置流程。

前提:确保系统启用 cgroup v2

若当前为 v1,可通过以下方式临时切换(重启失效):

# 卸载所有 v1 子系统
for m in $(mount | grep cgroup | grep -v unified | awk '{print $3}'); do umount $m; done
# 挂载 v2 统一层级
mount -t cgroup2 none /sys/fs/cgroup

步骤1:创建 cgroup 控制组

/sys/fs/cgroup 下创建目录(即创建一个 cgroup,内核会自动生成默认配置文件):

# 创建名为 "my-cgroup" 的控制组
mkdir /sys/fs/cgroup/my-cgroup
cd /sys/fs/cgroup/my-cgroup

# 查看自动生成的配置文件(包含所有子系统的控制参数)
ls
# 输出示例:cgroup.controllers  cgroup.max.depth  memory.max  cpu.max  ...

步骤2:配置资源限制

(1)限制 CPU 使用率(最多使用 1 个 CPU 核心)

cgroup v2 用 cpu.max 控制 CPU 绝对限制,格式为 配额/周期(单位:微秒,1 秒=1e6 微秒):

# 配置:周期 100ms(100000 微秒),配额 100ms(即 100% 占用 1 个核心)
echo "100000 100000" > cpu.max

# 若要限制为 50% CPU(0.5 个核心),配额设为 50ms:
# echo "50000 100000" > cpu.max

# 查看配置
cat cpu.max
(2)限制内存上限(最多使用 512MB 物理内存)

memory.max 控制内存上限(支持 K/M/G 单位):

# 限制物理内存最大 512MB(交换空间默认无限制,可通过 memory.swap.max 限制)
echo "512M" > memory.max

# 查看配置
cat memory.max

步骤3:将进程加入 cgroup

通过 cgroup.procs 文件写入进程 PID,即可将进程纳入该 cgroup 的资源控制:

# 假设要控制的进程 PID 为 1234
echo 1234 > cgroup.procs

# 验证进程是否在该 cgroup 中(查看 cgroup.procs 文件)
cat cgroup.procs

步骤4:监控 cgroup 资源使用

通过统计类文件查看资源使用情况:

# 查看 CPU 使用统计(单位:微秒)
cat cpu.stat

# 查看内存使用统计(已用内存、峰值等)
cat memory.stat

步骤5:删除 cgroup

先确保 cgroup 中无进程(cgroup.procs 为空),再删除目录:

# 清空进程(可选,若进程已退出则无需操作)
echo > cgroup.procs

# 删除 cgroup
rmdir /sys/fs/cgroup/my-cgroup

五、cgroup 的典型应用场景

  1. 容器技术:Docker、Kubernetes 利用 cgroup 实现容器的资源隔离(如 docker run --cpus 1 --memory 1G 本质是配置 cgroup);
  2. 系统资源管理:systemd 集成 cgroup,通过 serviceslice 控制服务的资源(如 systemctl set-property nginx.service CPUQuota=50%);
  3. 多租户隔离:云服务器(如阿里云 ECS)利用 cgroup 隔离不同租户的资源,避免单个租户占用过多资源;
  4. 测试环境限流:压测时限制测试进程的 CPU/内存使用,避免影响生产环境。

六、常见问题与注意事项

  1. 权限问题/sys/fs/cgroup 目录默认仅 root 可操作,普通用户需通过 sudo 或文件系统权限配置;
  2. 内存限制不生效:需确保内核启用 CONFIG_MEMCG 编译选项(主流发行版默认启用),且未禁用 memory 子系统;
  3. CPU 限制与核心数cpu.max 的配额不能超过周期(如周期 100ms 时,配额最大 100ms,对应 1 个核心),多核心需调整周期或配额;
  4. v1 与 v2 兼容性:老工具(如早期 docker 版本)可能不支持 v2,需切换回 v1 或升级工具;
  5. 子 cgroup 资源限制:子 cgroup 的资源上限不能超过父 cgroup(如父 cgroup 限制 1G 内存,子 cgroup 最多只能设 1G)。

总结

cgroup 是 Linux 内核的核心资源管理机制,通过“任务-控制组-子系统-层级”的架构,实现了对进程组的多维度资源控制。v2 版本简化了配置、解决了 v1 的设计缺陷,已成为主流场景的首选。无论是容器、虚拟化还是系统资源管理,cgroup 都是实现“资源可控”的关键技术,理解其原理和实操方法,能帮助更好地排查资源相关问题(如容器 OOM、CPU 占用过高)。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值