目录

一、CGroups——容器资源管理的内核核心

1. 本质与定位

2. 核心目标

二、CGroups 的核心功能

1. 资源使用限制(核心功能)

2. 资源优先级分配

3. 资源使用监控

4. 进程生命周期操作

5. 层次化结构支持

三、CGroups 关键子系统(资源管理模块)

四、CGroups 工作原理(从配置到生效)

1. 挂载 CGroups 文件系统

2. 创建控制组

3. 配置资源规则

4. 加入进程到控制组

5. 资源监控与生效验证

五、CGroups 在 Docker 中的应用

1. Docker 自动创建 CGroups 控制组

2. 支持的核心资源限制参数

3. 资源监控与查看

六、CGroups 的历史演进:v1 与 v2

1. v1 版本(2008 年,内核 2.6.24)

2. v2 版本(2016 年,内核 4.5)

七、CGroups 的核心价值与意义

1. 保障宿主机与容器的稳定性

2. 实现资源的精细化运营

3. 支撑容器编排平台的资源管理

总结


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.limitsresources.requests),最终都依赖 CGroups 实现,是编排平台的 “底层执行引擎”。


总结

CGroups 作为 Linux 内核的核心资源管理机制,通过 “子系统 + 文件系统接口” 的设计,实现了对进程组资源的 “限制、监控、调度”,与 Namespace 共同构成容器技术的两大基石 ——Namespace 负责 “隔离资源视图”,CGroups 负责 “控制资源使用”。无论是单机 Docker 容器,还是大规模 K8s 集群,CGroups 都是保障资源可控、系统稳定的底层核心,也是理解容器资源管理的关键技术点。

Logo

码道开发者社区,聚焦华为云码道 CodeArts 代码智能体,沉淀 Agent、Skill、鸿蒙开发实战内容,供开发者查阅资料、交流技术、分享工程实践

更多推荐