一、为什么需要 CGroup?(解决什么问题?)
1. 核心痛点
**Namespace(命名空间)**只能解决「隔离视图」的问题:
- 让容器看不到宿主机的进程、网络、文件系统
- 但无法限制资源使用
如果同一台宿主机上跑多个容器,其中一个容器跑 CPU 密集型 / 内存吃满的任务,会直接把宿主机的 CPU、内存占满,导致其他容器、甚至宿主机本身卡死,生产环境绝对不能出现这种情况。
2. CGroup 的核心作用
CGroup(Control Groups,控制组)是 Linux 内核的机制,专门解决资源限制、隔离、监控的问题:
把进程分组,给每个组分配「资源上限」,比如最多用 100M 内存、最多用 50% CPU,防止某个进程 / 容器占满宿主机资源,保证其他进程正常运行。
二、CGroup 核心知识点
1. CGroup 的 5 大核心功能
| 功能 | 大白话解释 |
|---|---|
| 1. 限制资源使用量 | 给进程组设资源上限(比如内存最多 100M、CPU 最多 50%),防止占满系统资源 |
| 2. 分配资源优先级 | 给不同组分配不同优先级,高优先级任务分更多 CPU 时间 |
| 3. 监控资源使用 | 记录组内进程的 CPU、内存使用情况,方便运维排查 |
| 4. 进程生命周期管理 | 支持挂起、恢复、终止组内所有进程 |
| 5. 层次化结构 | 支持组嵌套,形成树状结构(比如父组限制总资源,子组细分) |
2. CGroup 的子系统(资源管理模块)
CGroup 通过 ** 子系统(subsystem)** 管理不同类型的资源,/sys/fs/cgroup/目录下的文件夹就是各个子系统,核心常用子系统:
表格
| 子系统 | 作用 |
|---|---|
cpu |
限制 CPU 使用率,按比例分配 CPU 时间 |
memory |
限制内存使用量,设置内存 / 交换区上限(本次实验的核心) |
blkio |
限制块设备(磁盘)的 I/O 操作 |
devices |
控制组内进程对设备的访问权限 |
freezer |
挂起 / 恢复组内进程 |
net_cls |
标记网络数据包,用于流量控制 |
pids |
限制组内进程的最大数量 |
cpuacct |
统计组内进程的 CPU 使用情况 |
大白话:每个子系统对应一种资源,
memory子系统管内存,cpu子系统管 CPU,各司其职。
三、实战:用 CGroup 限制内存
1. 准备:内存吃满程序
// 核心逻辑:死循环,每次申请10MB内存,填随机数据,持续吃内存
// 直到内存耗尽被系统杀死,用来测试CGroup内存限制
- 不限制的话,会一直吃内存,直到宿主机内存耗尽,系统卡死
2. 目标
创建一个名为demo的 CGroup 内存组,限制组内进程最多用 100M 内存,让两个吃内存的程序在 100M 时被杀死,不影响宿主机。
3. 步骤
步骤 1:创建 CGroup 内存组
mkdir /sys/fs/cgroup/memory/demo/
- CGroup 是文件系统级别的管理 ,在
/sys/fs/cgroup/memory/下创建目录,就等于创建了一个内存控制组 - 内核会自动在目录下生成一堆配置文件(比如
memory.limit_in_bytes、memory.swappiness、tasks)
步骤 2:设置内存限制
# 限制最大内存为100MB(100*1024*1024=100000000字节)
echo "100000000" > /sys/fs/cgroup/memory/demo/memory.limit_in_bytes
# 禁止使用交换分区(swap),让限制更严格,演示效果更明显
echo "0" > /sys/fs/cgroup/memory/demo/memory.swappiness
memory.limit_in_bytes:内存上限,超过这个值,内核会杀死组内进程memory.swappiness:控制 swap 使用,设为 0 就是完全不用 swap,内存超了直接杀进程
步骤 3:把进程加入 CGroup(核心操作)
# 1. 打开两个bash终端,获取两个bash的PID
ps -ef | grep bash
# 2. 把两个bash的PID写入tasks文件,就等于把进程加入demo组
echo $$ >> /sys/fs/cgroup/memory/demo/tasks
tasks文件是 CGroup 的核心:把进程 PID 写入 tasks,就把进程加入了这个控制组- 之后在这两个 bash 里运行的所有程序(比如
./cgmemdemo),都会继承这个 CGroup 的内存限制
步骤 4:运行吃内存程序,验证限制
在两个 bash 里分别运行./cgmemdemo,效果如下:
- 程序会持续打印
10mb、20mb...80mb,到接近 100mb 时,被内核杀死(显示 Killed) - 两个程序都在 100M 左右被杀死,宿主机内存完全不受影响,完美验证了 CGroup 的限制效果
四、CGroup 的删除与历史
1. 如何取消 CGroup 限制
rmdir /sys/fs/cgroup/memory/demo/
- 直接删除 CGroup 目录,就等于取消限制
- 注意 :必须等
tasks文件里的所有进程都退出 / 转移到其他组,才能删除目录,否则会报错
2. CGroup 的历史
- 前身:2006 年 Google 工程师开发的
process containers项目,2007 年改名为control groups(CGroup) - 版本:
- v1:最初版本,2008 年并入 Linux 2.6.24 内核
- v2:Tejun Heo 重写,内核 4.5 版本引入,更高效、更灵活,现在容器普遍用 v2
- 容器应用:Docker、K8s 的资源限制(比如
docker run --memory=1g、--cpus=1),底层都是 CGroup 实现的
五、CGroup vs Namespace:容器的两大核心技术
| 技术 | 核心作用 | 解决的问题 | 大白话 |
|---|---|---|---|
| Namespace(命名空间) | 隔离视图 | 让进程看不到宿主机 / 其他容器的资源 | 给进程戴「滤镜」,只能看到自己的世界 |
| CGroup(控制组) | 限制资源 | 让进程不能占满宿主机的 CPU、内存等资源 | 给进程上「枷锁」,限制能使用的资源上限 |
容器的本质 = **Namespace(隔离视图) + CGroup(限制资源) + Rootfs(独立文件系统)**三者缺一不可,共同实现了容器的隔离、资源管控、环境一致性。
六、对应 Docker/K8s 的实际应用
你在 Docker 里用的资源限制,底层全是 CGroup:
docker run --memory=100m my-ml-app:底层就是创建一个 memory CGroup,限制内存 100Mdocker run --cpus=1 my-ml-app:底层就是创建一个 cpu CGroup,限制最多用 1 核 CPUdocker run --blkio-weight=500 my-ml-app:底层就是 blkio CGroup,限制磁盘 I/O 权重- K8s 的
resources.requests/limits,底层也是 CGroup,给 Pod 设置资源限制
七、总结
CGroup 是 Linux 内核的资源管理机制,通过将进程分组,对组内进程的 CPU、内存、磁盘 I/O 等资源进行限制、隔离和监控,是容器资源隔离的核心技术,Docker、K8s 的资源限制都基于 CGroup 实现。
,CGroup 是 Linux 内核的控制组机制,用来解决容器的资源限制问题。Namespace 解决了视图隔离,但无法限制资源,CGroup 通过子系统(比如 memory、cpu)给进程组设置资源上限,比如限制容器最多用 100M 内存、50% CPU,防止某个容器占满宿主机资源,保证系统稳定性。Docker 和 K8s 的资源限制,底层都是 CGroup 实现的,是容器技术的核心支柱之一。
八、补充:实验注意事项
- 必须用 root 权限操作 :CGroup 的配置需要 root 权限,普通用户无法修改
/sys/fs/cgroup/下的文件 - 进程继承 CGroup:把 bash 加入 CGroup 后,bash 里启动的所有子进程都会自动继承这个 CGroup 的限制
- v1 vs v2 的区别:现在大部分系统用 cgroup v2,目录结构和 v1 略有不同,但核心逻辑一致
- OOM Killer 的作用:当进程超过 CGroup 内存限制时,内核会触发 OOM Killer,杀死组内进程,保护系统