什么是 Linux 的控制组(Control Groups / cgroups)?它在 Docker 中起到什么作用?
在容器化技术(如 Docker)中,控制组(Control Groups,简称 cgroups) 是最核心的底层基石之一。
简单来说,如果把 Namespace(命名空间) 比作“隔离墙”(决定容器能看到什么),那么 cgroups 就是“资源限额表”(决定容器能使用多少资源)。
下面我们详细拆解 cgroups 的概念以及它在 Docker 中的关键作用。
一、 什么是 Linux cgroups?
cgroups(Control Groups) 是 Linux 内核提供的一种机制,用于限制、记录和隔离进程组所使用的物理资源(如 CPU、内存、磁盘 I/O、网络带宽等)。
cgroups 最初由 Google 的工程师在 2006 年发起,并在 2008 年合并入 Linux 内核(2.6.24 版本)。
cgroups 的四大核心功能:
- 资源限制(Resource Limiting):限制进程组使用的资源上限。例如:限制某个进程组最多只能使用 2GB 内存。
- 优先级分配(Prioritization):分配 CPU 占有份额或磁盘 I/O 带宽。例如:在 CPU 繁忙时,确保 A 进程组获得 70% 的 CPU 时间,B 进程组获得 30%。
- 资源审计(Accounting):监控和统计进程组的资源使用情况(用于计费或性能监控)。
- 进程控制(Control):可以挂起、恢复或重启整个进程组中的所有进程。
二、 cgroups 在 Docker 中起到什么作用?
Docker 容器本质上是宿主机上的一个普通进程。如果没有 cgroups,一个失控的容器可能会消耗掉宿主机上的所有 CPU 和内存,导致其他容器甚至宿主机崩溃(即“嘈杂邻居”效应,Noisy Neighbor)。
Docker 利用 cgroups 实现了对容器的“资源配额”和“度量”。 具体表现在以下几个方面:
1. 内存限制(Memory Limits)
Docker 可以限制容器能使用的最大物理内存和 Swap(交换分区)。
- 作用:防止单个容器因为内存泄露(OOM - Out of Memory)而榨干宿主机的内存,导致宿主机崩溃。
- Docker 命令示例:bash
# 限制容器最多只能使用 512MB 内存 docker run -d -m 512m nginx
2. CPU 限制(CPU Limits)
Docker 可以限制容器使用的 CPU 核心数或 CPU 时间片比例。
- 作用:防止某个计算密集型容器独占 CPU,确保其他容器有足够的 CPU 资源运行。
- Docker 命令示例:bash
# 限制容器最多只能使用 1.5 个 CPU 核心 docker run -d --cpus="1.5" nginx # 限制容器的 CPU 权重(在 CPU 繁忙时按比例分配) docker run -d --cpu-shares=512 nginx
3. 磁盘 I/O 限制(Block I/O Limits)
Docker 可以限制容器读写磁盘的速度(IOPS 或吞吐量)。
- 作用:防止某个容器进行频繁的读写操作(如数据库备份、大文件下载),导致磁盘 I/O 跑满,影响其他容器的响应速度。
- Docker 命令示例:bash
# 限制容器对 /dev/sda 的写速度不超过 10MB/s docker run -d --device-write-bps /dev/sda:10mb ubuntu
4. 进程数限制(PIDs Limit)
Docker 可以限制容器内能创建的最大进程/线程数量。
- 作用:防止容器内遭遇“fork 炸弹”(一种恶意程序,通过无限自我复制进程来耗尽系统资源)。
- Docker 命令示例:bash
# 限制容器内最多只能运行 100 个进程 docker run -d --pids-limit 100 nginx
三、 在 Docker 中如何查看 cgroups?
在 Linux 系统中,cgroups 是通过虚拟文件系统(通常挂载在 /sys/fs/cgroup)来展示和操作的。
当你启动一个 Docker 容器时,Docker 会在 /sys/fs/cgroup 下为该容器创建一个专属的子目录。
动手查看:
- 启动一个限制了内存的容器:bash
docker run -d --name test-cgroup -m 256m nginx - 获取该容器的完整 ID:bash
docker inspect --format='{{.Id}}' test-cgroup # 假设输出为:a1b2c3d4... - 进入宿主机的 cgroup 目录查看(以 cgroups v1 为例):你会看到输出结果正好是bash
cat /sys/fs/cgroup/memory/docker/<容器完整ID>/memory.limit_in_bytes268435456字节(即 256MB)。这就是 Docker 底层通过 cgroups 限制容器内存的铁证。
总结
- Namespace 解决了 “安全隔离” 的问题(让容器以为自己独占了系统)。
- cgroups 解决了 “资源分配” 的问题(防止容器之间互相抢占资源)。
这两大 Linux 内核技术共同构成了 Docker 容器的核心基石。