【Docker】(四)Docker三大核心技术之CGroup
目录
Linux CGroups(Control Groups,控制组)是内核提供的一种进程资源管理机制,能够对进程组的 CPU、内存、磁盘 I/O 等系统资源进行限制、监控、优先级分配,从根本上解决多进程(如容器)在同一宿主机上的资源争用问题,是 Docker、Kubernetes 等容器技术实现 “资源可控” 的核心底层支撑。
一、CGroups——容器资源管理的内核核心
1. 本质与定位
CGroups 并非独立的软件,而是内核级别的 “资源分组管理框架”—— 通过将系统中所有进程按照需求划分到不同 “控制组”(CGroup),为每个组分配特定的资源规则(如内存上限、CPU 占比),使内核在调度资源时遵循这些规则,最终实现 “资源按需分配与隔离”。
其核心定位是弥补 Namespace 仅 “隔离资源视图” 的不足:Namespace 让容器 “看不到” 外部资源,而 CGroups 让容器 “用不了超出限制的资源”,二者协同构成容器 “隔离 + 限制” 的完整资源管理体系。
2. 核心目标
- 避免资源争抢:防止单个进程 / 容器过度占用资源(如 CPU 密集型容器占满宿主机 CPU),导致其他进程 / 容器性能骤降或不可用;
- 资源精细化分配:按业务优先级为不同进程组分配资源(如给核心服务分配 2 核 CPU,给测试服务分配 0.5 核 CPU);
- 资源使用监控:实时记录进程组的资源消耗(如内存使用量、CPU 耗时),为运维和调优提供数据支撑;
- 保障系统稳定:在资源耗尽前触发保护机制(如内存超限杀死进程),避免宿主机因资源耗尽崩溃。
二、CGroups 的核心功能
CGroups 通过 “子系统(Subsystem)” 实现对不同资源的管理,核心功能围绕 “资源控制、监控、调度” 展开,具体包括五大能力:
1. 资源使用限制(核心功能)
对进程组的特定资源设置 “硬上限”,一旦超出限制,内核会通过 “拒绝分配” 或 “触发保护机制” 强制干预:
- CPU 限制:限制进程组的 CPU 使用率(如最多使用 1 个核心)、CPU 时间片占比(如在多核心环境中占 50% 时间片);
- 内存限制:限制进程组的物理内存使用上限(如最多 512MB)、交换空间(Swap)上限,超出时触发 OOM(Out Of Memory)杀死进程;
- 磁盘 I/O 限制:限制进程组对磁盘的读写速率(如读速率不超过 100MB/s)、IOPS(每秒 I/O 操作次数),避免单个进程拖慢磁盘整体性能;
- 设备访问限制:控制进程组对硬件设备(如 /dev/sda 磁盘、/dev/usb 设备)的访问权限(只读 / 读写 / 禁止访问),提升安全性。
2. 资源优先级分配
为不同进程组设置资源使用优先级,在资源紧张时,高优先级组优先获得资源:
- CPU 优先级:通过 “CPU 份额(shares)” 分配优先级(默认每个组 1024 份额),如 A 组份额 2048、B 组 1024,CPU 紧张时 A 组会获得 2/3 的 CPU 时间;
- 磁盘 I/O 优先级:通过 “权重(weight)” 设置 I/O 优先级,高权重组在磁盘繁忙时优先完成读写操作。
3. 资源使用监控
实时记录进程组的资源消耗数据,以 “文件读写” 的方式对外暴露,便于工具(如 docker stats、kubectl top)采集:
- CPU 监控:记录进程组的总 CPU 耗时、每个核心的使用情况(如 /sys/fs/cgroup/cpu/[组名]/cpuacct.usage);
- 内存监控:记录进程组的当前内存使用量、峰值使用量(如 /sys/fs/cgroup/memory/[组名]/memory.usage_in_bytes、memory.max_usage_in_bytes);
- 磁盘 I/O 监控:记录读写字节数、IOPS 等(如 /sys/fs/cgroup/blkio/[组名]/blkio.io_service_bytes)。
4. 进程生命周期操作
对控制组内的所有进程执行批量操作,简化进程管理:
- 挂起与恢复:通过 freezer 子系统暂停组内所有进程(如
echo FROZEN > /sys/fs/cgroup/freezer/[组名]/freezer.state),需恢复时写入THAWED; - 批量终止:删除控制组目录时,若组内仍有进程,内核可自动终止这些进程(需开启 notify_on_release 机制)。
5. 层次化结构支持
CGroups 支持 “组嵌套”,形成树状层次结构,父组的资源限制会自动传递给子组,实现精细化的资源分配:
- 例如:创建父组
web-services并限制 CPU 为 2 核,再在其下创建子组nginx(限制 CPU 1 核)和tomcat(限制 CPU 1 核),子组总资源不会超出父组限制; - 优势:适配复杂业务架构(如 K8s 中 “Node → Namespace → Pod” 的资源层级),便于统一管理和资源配额分配。
三、CGroups 关键子系统(资源管理模块)
CGroups 按 “资源类型” 拆分出多个独立子系统(Subsystem),每个子系统负责一类资源的管理,所有子系统通过统一的文件系统接口对外提供配置能力。常见子系统及功能如下:
| 子系统名称 | 管理资源类型 | 核心配置文件(示例) | 关键作用 |
|---|---|---|---|
| cpu | CPU 调度与使用率 | cpu.cfs_quota_us(CPU 配额)、cpu.shares(CPU 份额) | 限制 CPU 核心数、控制优先级 |
| cpuacct | CPU 使用统计 | cpuacct.usage(总 CPU 耗时)、cpuacct.usage_percpu(每核耗时) | 监控进程组 CPU 消耗 |
| memory | 物理内存与交换空间 | memory.limit_in_bytes(内存上限)、memory.swappiness(交换空间策略) | 限制内存使用,触发 OOM 保护 |
| blkio | 块设备 I/O(磁盘、SSD 等) | blkio.throttle.read_bps_device(读速率限制)、blkio.weight(I/O 权重) | 限制磁盘读写速率,分配 I/O 优先级 |
| devices | 硬件设备访问权限 | devices.allow(允许访问的设备)、devices.deny(禁止访问的设备) | 控制进程对设备的读写权限 |
| freezer | 进程挂起与恢复 | freezer.state(状态:FROZEN/THAWED) | 批量暂停 / 恢复组内进程 |
| net_cls | 网络流量分类 | net_cls.classid(流量标记 ID) | 为网络数据包打标签,配合 tc 工具做流量控制 |
| pids | 进程数量 | pids.max(最大进程数)、pids.current(当前进程数) | 限制组内进程总数,防止 fork 炸弹 |
| hugetlb | 大页内存(HugeTLB) | hugetlb.1GB.limit_in_bytes(1GB 大页上限) | 管理大页内存分配,优化数据库等内存密集型应用 |
这些子系统默认挂载在 /sys/fs/cgroup 目录下,通过 “文件操作” 即可配置(如 echo 命令修改配置文件),无需复杂的 API 调用。
四、CGroups 工作原理(从配置到生效)
CGroups 基于 “文件系统” 实现,其工作流程可概括为 “挂载子系统 → 创建控制组 → 配置资源规则 → 加入进程 → 生效监控”,具体步骤如下:
1. 挂载 CGroups 文件系统
Linux 启动时,内核会自动将 CGroups 文件系统挂载到 /sys/fs/cgroup,每个子系统对应一个目录(如 /sys/fs/cgroup/memory 对应 memory 子系统):
# 查看 CGroups 挂载情况
mount | grep cgroup
# 输出示例:tmpfs on /sys/fs/cgroup type tmpfs (ro,nosuid,nodev,noexec,mode=755)
# 每个子系统目录下包含默认组(root 组)和配置文件
2. 创建控制组
创建控制组的本质是 “在子系统目录下新建文件夹”,内核会自动为该文件夹生成一套默认的资源配置文件:
# 在 memory 子系统下创建名为 "nginx-group" 的控制组
mkdir /sys/fs/cgroup/memory/nginx-group
# 进入目录查看自动生成的配置文件
ls /sys/fs/cgroup/memory/nginx-group
# 输出包含:memory.limit_in_bytes(内存上限)、memory.usage_in_bytes(当前使用量)等
3. 配置资源规则
通过 “写入配置文件” 设置资源限制,配置会立即生效:
# 限制 "nginx-group" 的内存上限为 512MB(512*1024*1024 = 536870912 字节)
echo 536870912 > /sys/fs/cgroup/memory/nginx-group/memory.limit_in_bytes
# 禁止使用交换空间(swappiness=0)
echo 0 > /sys/fs/cgroup/memory/nginx-group/memory.swappiness
4. 加入进程到控制组
将进程的 PID 写入控制组的 tasks 文件,该进程及后续创建的子进程会自动加入此控制组,受资源规则约束:
# 启动 nginx 进程,获取其 PID(假设为 1234)
nginx -g "daemon on;"
# 将 PID=1234 加入 "nginx-group"
echo 1234 > /sys/fs/cgroup/memory/nginx-group/tasks
# 验证:查看该进程的内存限制是否生效
cat /proc/1234/cgroup | grep memory
# 输出包含:memory:/nginx-group(表示进程属于 nginx-group 控制组)
5. 资源监控与生效验证
通过读取配置文件中的 “使用量” 字段,实时监控资源消耗,若超出限制,内核会触发保护机制:
# 查看 nginx-group 的当前内存使用量
cat /sys/fs/cgroup/memory/nginx-group/memory.usage_in_bytes
# 若使用量超过 512MB,内核会杀死 nginx 进程(触发 OOM),并在日志中记录
dmesg | grep -i "out of memory"
五、CGroups 在 Docker 中的应用
Docker 完全依赖 CGroups 实现容器的资源限制,用户通过 docker run 或 docker-compose 设置的资源参数,最终都会转化为 CGroups 子系统的配置,具体流程如下:
1. Docker 自动创建 CGroups 控制组
启动容器时,Docker 会在 /sys/fs/cgroup 各子系统目录下,创建以 “docker/[容器 ID]” 命名的控制组:
- 例如启动一个 nginx 容器(ID 为 abc123),Docker 会创建
/sys/fs/cgroup/memory/docker/abc123、/sys/fs/cgroup/cpu/docker/abc123等目录; - 每个控制组的配置文件会根据用户指定的资源参数自动填充(如
--memory=1G对应memory.limit_in_bytes=1073741824)。
2. 支持的核心资源限制参数
Docker 提供简洁的命令行参数,屏蔽了 CGroups 底层配置的复杂性,常见参数如下:
| Docker 参数 | 对应 CGroups 子系统 | 作用 | 示例 |
|---|---|---|---|
--memory / --memory-limit |
memory | 限制容器内存上限 | docker run --memory=512M nginx |
--memory-swap |
memory | 限制内存 + 交换空间总上限 | docker run --memory=512M --memory-swap=1G nginx |
--cpus |
cpu | 限制容器可使用的 CPU 核心数 | docker run --cpus=0.5 nginx(最多使用 0.5 核) |
--cpu-shares |
cpu | 设置 CPU 优先级份额(默认 1024) | docker run --cpu-shares=2048 nginx(高优先级) |
--device-read-bps |
blkio | 限制设备读速率 | docker run --device-read-bps=/dev/sda:100MB nginx |
--pids-limit |
pids | 限制容器内最大进程数 | docker run --pids-limit=100 nginx(最多 100 个进程) |
3. 资源监控与查看
Docker 提供 docker stats 命令,实时查看容器的资源消耗,其数据来源正是 CGroups 子系统的监控文件:
# 查看所有运行中容器的资源消耗
docker stats
# 输出包含:CPU 使用率、内存使用量/上限、网络 I/O、磁盘 I/O 等,数据直接读取 CGroups 的 cpuacct、memory、blkio 子系统
六、CGroups 的历史演进:v1 与 v2
CGroups 经历了两个主要版本,v2 是对 v1 的重构与优化,解决了 v1 的设计缺陷,目前已成为 Docker、Kubernetes 的主流选择。
1. v1 版本(2008 年,内核 2.6.24)
- 设计特点:子系统独立管理,每个子系统有自己的层次结构,配置文件分散;
- 缺陷:
- 子系统层次结构不统一,导致资源管理复杂(如父组对 CPU 的限制无法直接传递给内存子系统);
- 部分子系统功能重叠(如 cpu 和 cpuacct 分别负责 CPU 限制和统计,需手动关联);
- 不支持 “统一资源视图”,无法整体管理多类资源。
2. v2 版本(2016 年,内核 4.5)
- 核心改进:
- 统一层次结构:所有子系统共享一套控制组层次,父组的资源限制自动应用于所有子系统,简化配置;
- 合并功能重叠子系统:如 cpu 和 cpuacct 合并为 cpu 子系统,同时支持限制与统计;
- 支持 “资源控制器”:可动态启用 / 禁用子系统,按需加载资源管理能力;
- 更好的安全性:支持对控制组的权限控制,防止非授权修改资源规则;
- 当前支持:Docker 20.10+、Kubernetes 1.24+ 已默认支持 CGroups v2,主流 Linux 发行版(Ubuntu 22.04+、CentOS Stream 9+)也默认启用 v2。
七、CGroups 的核心价值与意义
CGroups 是容器技术从 “可用” 走向 “可靠” 的关键支撑,其价值主要体现在三个方面:
1. 保障宿主机与容器的稳定性
通过资源限制,防止单个容器 “暴饮暴食” 占用宿主机资源,避免因一个容器故障导致整个宿主机崩溃,是多容器共享宿主机的 “安全保障”。
2. 实现资源的精细化运营
在云原生环境中,通过 CGroups 可按业务需求分配资源(如核心服务独占 2 核 CPU,非核心服务共享 1 核 CPU),提升资源利用率,降低硬件成本。
3. 支撑容器编排平台的资源管理
Docker Swarm、Kubernetes 等编排平台的 “资源调度” 功能(如 K8s 的 resources.limits、resources.requests),最终都依赖 CGroups 实现,是编排平台的 “底层执行引擎”。
总结
CGroups 作为 Linux 内核的核心资源管理机制,通过 “子系统 + 文件系统接口” 的设计,实现了对进程组资源的 “限制、监控、调度”,与 Namespace 共同构成容器技术的两大基石 ——Namespace 负责 “隔离资源视图”,CGroups 负责 “控制资源使用”。无论是单机 Docker 容器,还是大规模 K8s 集群,CGroups 都是保障资源可控、系统稳定的底层核心,也是理解容器资源管理的关键技术点。
更多推荐


所有评论(0)