管理容器的资源:深入理解 Cgroup 机制
管理容器的资源:深入理解 Cgroup 机制
- 🧩 管理容器的资源:深入理解 Cgroup 机制
- 🧠 一、Cgroup 是什么?
- ⚙️ 二、为什么容器需要 Cgroup?
- 🔍 三、Cgroup 的结构与版本
- 🪜 1. 树状层级结构
- 🧩 2. 控制器类型(常用)
- 🧬 3. Cgroup v1 与 v2 区别
- 🧱 四、Docker 如何使用 Cgroup?
- ⚡ 五、Docker 中的资源限制实战
- 💾 限制内存使用
- 🧮 限制 CPU 使用
- 🧩 限制进程数量
- 🧱 限制磁盘 I/O
- 🔬 六、手动使用 Cgroup 限制资源(原生命令演示)
- 1️⃣ 创建控制组
- 2️⃣ 限制内存
- 3️⃣ 启动测试进程
- 📊 七、资源监控与调优
- 💡 八、Cgroup 与 Namespace 的关系
- 🧭 九、总结
- 📚 延伸阅读
🧩 管理容器的资源:深入理解 Cgroup 机制
Docker 能够高效地运行多个容器、并精确地控制它们的 CPU、内存、I/O 等资源,
这背后的“魔法”来自 Linux 的 Cgroup(Control Groups)。本文将带你深入理解 Cgroup 的原理、类别、Docker 如何使用它,以及如何亲手限制容器资源。
🧠 一、Cgroup 是什么?
Cgroup(Control Groups) 是 Linux 内核提供的一种机制,用于:
- 限制(Limit)
- 统计(Account)
- 隔离(Isolate)
一组进程对系统资源(如 CPU、内存、I/O、进程数等)的使用情况。
换句话说,Cgroup 是 Linux 系统的“资源管理底层”,
Docker、Kubernetes、systemd 都是通过它来实现容器化资源控制的。
⚙️ 二、为什么容器需要 Cgroup?
如果没有 Cgroup,所有容器运行在宿主机上时:
- 容易出现某个容器独占 CPU;
- 内存泄漏会导致宿主机 OOM;
- I/O 密集型容器可能拖慢整个系统。
通过 Cgroup,Docker 能为每个容器设定“上限”,例如:
- CPU 只能用 20%
- 内存最多 512MB
- 最多允许 100 个进程
- 限制磁盘写入速率 10MB/s
🧩 这样,每个容器都像被分配了独立的资源配额,互不干扰。
🔍 三、Cgroup 的结构与版本
🪜 1. 树状层级结构
Cgroup 将系统中的进程组织成一个树状结构。
每个节点是一个 控制组(control group),每个组可绑定若干控制器。
示意图:
cgroup├── docker│ ├── container_1│ └── container_2└── system.slice
每个控制组可以定义自己的资源限制文件,例如:
/sys/fs/cgroup/docker/container_1/memory.max
/sys/fs/cgroup/docker/container_1/cpu.max
🧩 2. 控制器类型(常用)
| 控制器 | 说明 |
|---|---|
| cpu | 限制进程使用 CPU 的时间 |
| cpuacct | 统计 CPU 使用量 |
| memory | 限制内存使用 |
| pids | 限制进程数 |
| blkio | 限制磁盘 I/O 速率 |
| devices | 控制设备访问权限 |
| cpuset | 控制进程可运行的 CPU 核心 |
🧬 3. Cgroup v1 与 v2 区别
| 对比项 | v1 | v2 |
|---|---|---|
| 控制器结构 | 各自独立 | 统一管理 |
| 层级模型 | 控制器可挂载多次 | 单一树结构 |
| 文件接口 | 分散复杂 | 简洁一致 |
| Docker 默认 | 旧版使用 v1 | 新版全面支持 v2 |
📌 新系统(如 Ubuntu 22+、RHEL 9+)默认使用 Cgroup v2。
🧱 四、Docker 如何使用 Cgroup?
Docker 通过 libcontainer 与内核交互,为每个容器创建独立的控制组:
示意图:
/sys/fs/cgroup/├── system.slice├── user.slice└── docker/├── 2b8f2a1b.../│ ├── cpu.max│ ├── memory.max│ └── pids.max└── ...
这些文件中保存的就是资源配额数据。
当容器进程启动时,Docker 会把它加入对应的 cgroup 中。
⚡ 五、Docker 中的资源限制实战
Docker 的资源限制其实就是对 Cgroup 文件的封装。
例如:
💾 限制内存使用
docker run -d --name mem_test --memory=200m ubuntu sleep 1000
效果:容器最大只能用 200MB 内存。
超过时,系统会触发 OOM(Out Of Memory) 杀死容器进程。
🧮 限制 CPU 使用
docker run -d --name cpu_test --cpus=0.5 ubuntu sleep 1000
效果:容器最多使用 50% CPU 时间。
🧩 限制进程数量
docker run -d --name pids_test --pids-limit=50 ubuntu sleep 1000
效果:容器最多可创建 50 个进程,防止 fork 炸弹。
🧱 限制磁盘 I/O
docker run -d --name io_test --device-write-bps /dev/sda:10mb ubuntu dd if=/dev/zero of=/tmp/test bs=1M count=100
效果:磁盘写入速度被限制为 10MB/s。
🔬 六、手动使用 Cgroup 限制资源(原生命令演示)
下面我们动手体验下 原生 cgroup 操作,理解 Docker 背后做了什么。
1️⃣ 创建控制组
sudo mkdir /sys/fs/cgroup/testgroup
2️⃣ 限制内存
echo $((100*1024*1024)) | sudo tee /sys/fs/cgroup/testgroup/memory.max
3️⃣ 启动测试进程
stress --vm 1 --vm-bytes 200M --timeout 30s &
echo $! | sudo tee /sys/fs/cgroup/testgroup/cgroup.procs
效果:该进程被限制为 100MB 内存,超过时会被系统 OOM 杀死。
📊 七、资源监控与调优
查看 cgroup 使用状态:
cat /sys/fs/cgroup/testgroup/memory.current
cat /sys/fs/cgroup/testgroup/cpu.stat
在 Docker 中查看容器资源使用:
docker stats
示例输出:
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O
c72bdf13e mem_test 49.7% 180.4MiB / 200MiB 90.2% 1.5kB / 0B
💡 八、Cgroup 与 Namespace 的关系
| 功能 | 机制 | 说明 |
|---|---|---|
| 隔离 | Namespace | 控制容器“能看到什么” |
| 限制 | Cgroup | 控制容器“能用多少” |
🧠 一句话理解:
Namespace 提供“边界”,Cgroup 提供“配额”。
🧭 九、总结
| 功能 | Cgroup 控制项 | Docker 参数 |
|---|---|---|
| CPU | cpu.max | --cpus |
| 内存 | memory.max | --memory |
| 进程数 | pids.max | --pids-limit |
| I/O | io.max | --device-read-bps / --device-write-bps |
✅ Cgroup 是容器资源管理的核心基础
✅ Docker、Kubernetes 都是基于它构建的高层封装
✅ 理解 Cgroup = 理解容器资源管理的本质
📚 延伸阅读
- Linux Cgroup v2 官方文档
- Docker 官方:Runtime Resource Constraints
- systemd Cgroup 集成说明
🧩 一句话记忆:
Cgroup 是容器的“资源警察”,
负责限制、统计、调度一切可被度量的系统资源。
