Skip to content
60.Docker»30.Cgroups»LV001-Cgroups简介.md

LV001-Cgroups简介

使用不同的 Namespace,可以实现容器中的进程看不到别的容器的资源,但是有一个问题,容器内的进程仍然可以任意地使用主机的 CPU 、内存等资源,如果某一个容器使用的主机资源过多,可能导致主机的资源竞争,进而影响业务。那如果我们想限制一个容器资源的使用(如 CPU、内存等)应该如何做呢?

一、Cgroups

1. 什么是 Cgroups

Cgroups 是 control groups 的缩写,是 Linux 内核提供的一种可以限制(Limit),统计(Account),隔离(Isolate)进程组(process groups)所使用物理资源的机制。最初由 google 工程师提出,后来被整合进 Linux 的内核。因此,Cgroups 为容器实现虚拟化提供了基本保证,是构建 Docker, LXC 等一系列虚拟化管理工具的基石。

手撕Linux Cgroups —— Cgroups实战分析以及在Docker中的应用

在 2006 年,Google 的工程师( Rohit Seth 和 Paul Menage 为主要发起人) 发起了这个项目,起初项目名称并不是 cgroups,而被称为进程容器(process containers)。在 2007 年 cgroups 代码计划合入 Linux 内核,但是当时在 Linux 内核中,容器(container)这个词被广泛使用,并且拥有不同的含义。为了避免命名混乱和歧义,进程容器被重名为 cgroups,并在 2008 年成功合入 Linux 2.6.24 版本中。cgroups 目前已经成为 systemd、Docker、Linux Containers(LXC) 等技术的基础。

这里还有1份官方文档可以参考:Control Group v2 — The Linux Kernel documentation

2. 为什么容器需要 Cgroups

如果没有 Cgroup,所有容器运行在宿主机上时:

  • 容易出现某个容器独占 CPU;

  • 内存泄漏会导致宿主机 OOM;

  • I/O 密集型容器可能拖慢整个系统。

通过 Cgroup,Docker 能为每个容器设定“上限”,例如:

  • CPU 只能用 20%
  • 内存最多 512MB
  • 最多允许 100 个进程
  • 限制磁盘写入速率 10MB/s

这样,每个容器都像被分配了独立的资源配额,互不干扰。

3. 提供了哪些功能

cgroups 主要提供了如下功能。

  • 资源限制: 限制资源的使用量,例如我们可以通过限制某个业务的内存上限,从而保护主机其他业务的安全运行。
  • 优先级控制:不同的组可以有不同的资源( CPU 、磁盘 IO 等)使用优先级。
  • 审计:计算控制组的资源使用情况。
  • 控制:控制进程的挂起或恢复。

二、基本概念

1. task

task 就是系统的一个进程,在 Cgroups 中叫 task 而已。

2. 三个核心概念

cgroups 功能的实现依赖于三个核心概念:子系统、控制组、层级树。

  • 子系统(subsystem):是一个内核的组件,一个子系统代表一类资源调度控制器。例如内存子系统可以限制内存的使用量,CPU 子系统可以限制 CPU 的使用时间。
  • 控制组(cgroup):表示一组进程和一组带有参数的子系统的关联关系。例如,一个进程使用了 CPU 子系统来限制 CPU 的使用时间,则这个进程和 CPU 子系统的关联关系称为控制组。
  • 层级树(hierarchy):是由一系列的控制组按照树状结构排列组成的。这种排列方式可以使得控制组拥有父子关系,子控制组默认拥有父控制组的属性,也就是子控制组会继承于父控制组。比如,系统中定义了一个控制组 c1,限制了 CPU 可以使用 1 核,然后另外一个控制组 c2 想实现既限制 CPU 使用 1 核,同时限制内存使用 2G,那么 c2 就可以直接继承 c1,无须重复定义 CPU 限制。

cgroups 的三个核心概念中,子系统是最核心的概念,因为子系统是真正实现某类资源的限制的基础。

3.1 subsystem

subsystem 就是一个资源调度控制器(Resource Controller)。比如 CPU 子系统可以控制 CPU 时间分配,内存子系统可以限制内存使用量。

每个 subsystem 背后都有相应的内核模块来配合它完成对资源的控制。比如对 cpu 资源的限制是通过进程调度模块根据 cpu 子系统的配置来完成的;对内存资源的限制则是内存模块根据 memory 子系统的配置来完成的,而对网络数据包的控制则需要 Traffic Control 子系统来配合完成。cgroups 为每种可以控制的资源定义了一个子系统。

典型的子系统介绍如下:

(1)cpu: 主要限制进程的 cpu 使用率。

(2)cpuacct: 可以统计 cgroups 中的进程的 cpu 使用报告。

(3)cpuset: 可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。

(4)memory: 可以限制进程的 memory 使用量。

(5)blkio: 可以限制进程的块设备 io。

(6)devices: 可以控制进程能够访问某些设备。

(7)net_cls: 可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。

(8)freezer: 可以挂起或者恢复 cgroups 中的进程。

3.2 cgroup

cgroup 是 Cgroups 中的资源控制的单位。cgroup 表示按照某种资源控制标准划分而成的任务组,可以包含一个或多个 subsystem。如果把一个 task 加入到一个 cgroup 中,那么这个 task 使用的资源将受到该 cgroup 中指定的标准限制。

cgroup 有两个版本:cgroup v1cgroup v2。以下是判断系统当前使用的 cgroup 版本的几种方法:

shell
# 1. mount: 如果输出中包含多个以 cgroup 开头的挂载点(如 cpu、memory 等),则为 cgroup v1。如果输出中只有一个 cgroup2 挂载点,则为 cgroup v2。
mount | grep cgroup

# 2. /proc/cmdline, 如果输出包含 systemd.unified_cgroup_hierarchy = 1 或 unified_cgroup_hierarchy = 1,则为 cgroup v2。果没有该参数或值为 0,则为 cgroup v1。
cat /proc/cmdline

两个版本对比如下:

对比项 v1 v2
控制器结构 各自独立 统一管理
层级模型 控制器可挂载多次 单一树结构
文件接口 分散复杂 简洁一致
Docker 默认 旧版使用 v1 新版全面支持 v2

3.3 hierarchy

hierarchy 由一系列 cgroup 以一个树状结构排列而成,每个 hierarchy 通过绑定对应的 subsystem 进行资源调度。hierarchy 中的 cgroup 节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个 hierarchy。hierarchy 的树状结构在用户态的表现形态为文件系统的层级结构,用户操作 hierarchy 就像创建文件夹,修改文件一样。

就类似这样:

shell
cgroup
 ├── docker
    ├── container_1
    └── container_2
 └── system.slice

参考资料

(9 封私信) 手撕 Linux Cgroups —— Cgroups 实战分析以及在 Docker 中的应用 - 知乎

Docker 底层:cgroups 实现资源限制 - 拾月凄辰 - 博客园

管理容器的资源:深入理解 Cgroup 机制-CSDN 博客

莫道桑榆晚 为霞尚满天.