2

容器底层-Cgroups 的使用

 3 years ago
source link: https://my.oschina.net/u/3872630/blog/4833371
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
容器底层-Cgroups 的使用

Linux Cgroups(Linux Control Group)是 Linux 内核中用来为进程设置资源限制的一个功能。它最主要的作用就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等。此外,Cgroups 还能够对进程进行优先级设置、审计,以及将进程挂起和恢复等操作。

那么为什么除了 Namespace 之外还需要 Cgroups 呢?因为虽然容器里的 1 号进程只能看到容器里的情况,但是在宿主机上,它作为 100 号进程(比如宿主机上它的 PID 是 100)与其他所有进程之间依然是平等的竞争关系。也就是说,虽然 100 号进程表面上被隔离了起来,但是它能够使用的资源(比如 CPU、内存)是全部的,它可能把所有资源耗光。那么这样显然不是一个容器应该表现出来的合理行为。

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即操作接口是以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。我们可以通过 mount 命令来查看一下,可以发现输出结果是一系列文件系统目录。

2d5de8e6-8865-4e49-bc9d-b3727d7c30a3.png

我们查看 /sys/fs/cgroup 的时候还可以看到一系列子目录,这些子目录又被称为子系统。这些都是我这台机器上当前可以被 Cgroups 进行限制的资源种类。比如:

  • cpu 只要限制 CPU 的使用时间
  • cpuset 为进程分配单独的 CPU 核和对应的内存节点
  • memory 为进程设定内存使用的限制
  • blkio 块设备设定 IO 限制,一般用于磁盘等设备
917f0a2d-93c3-4289-a105-b94eb4199fb3.png

而在子目录下面可以看到该子系统对应的资源可以被限制的方法,比如对于 CPU 子系统来说,我们可以看到如下几个配置文件。

fc106657-22e0-4108-9f11-9e1877fa8a38.png

其中 cpu.cfs_period_us 和 cpu.cfs_quota_us 这两个文件组合使用可以限制进程在长度为 cfs_period 的一段时间内,只能被分配到总量为 cfs_quota 的 CPU 时间。

Cgoups 配置示例

下面基于 Cgroups 提供的操作接口进行配置,我们先在相应的子系统中再创建一个目录,比如 container ,这个目录就被称为“控制组”。当将这个目录创建好了之后,你会发现这个目录已经生成了该子系统对应的资源限制文件。

e2eef4f9-ad41-4113-a3c8-6c37d87ee3f1.png

接下去,我们通过修改 container 中的文件内容来设置限制。比如向 container 中的 cpu.cfs_quota_us 中写入 20 ms,也就是 20000,就表示每 cpu_period_us (100ms)被控制组限制的进程只能使用 20ms 的 CPU 时间。

接下去我们把要限制的进程 PID 写入 container 目录中的 tasks 文件中,那么该设置对要限制的进程就有效了。

fab8af54-8fd9-4a91-955f-f51635f71923.png6e78c484-52c5-4e39-8084-3c8a233dc452.png

Docker 实现

对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(也就是创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 写入到这个控制组的 tasks 文件中即可。而控制组中的资源限制要填上什么值,就要看用户执行 docker run 时指定的参数内容。在 Docker 主机中,每个子系统下面都有 docker 控制组。

d13f4fff-3a36-45b7-a53d-71d86b71636c.png

下面我们来演示 docker 进行设置的效果,就会在 CPU 子系统的 docker 控制组中进行相关的设置。

docker run -it --rm --cpu-period=100000 --cpu-quota=20000 -d alpine sleep 500s

如下所示,docker 还会在 docker 控制组创建一个新的目录,在这个目录中对资源进行设置,从而达到限制资源使用的效果。

1eae598d-ba8d-42d1-8566-88a4b57a0518.png

跟 Namespace 情况类似,Cgoups 对资源的限制能力也有很多不完善的地方,其中被提及最多的是 /proc 文件系统的问题。/proc 目录存储着当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

但是,如果你在容器里执行 top 指令,就会发现,它显示的信息居然还是宿主机的 CPU 和内存数据。这是因为  /proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,所以它返回的还是整个宿主机的。那么这个问题会导致,容器内的应用程序读取到的 CPU 核数、可用内存等信息还是宿主机的,而不是做了限制之后的。这就是容器相比较于虚拟机另一个不尽如人意的地方。

当然,为了解决上面的那个问题。直观的做法就是容器不挂载宿主机的该目录就可以了,那么实际上可以通过 lxcfs 来实现隔离,lxcfs 在宿主机上维护进程组的信息,然后容器启动的时候将 lxcfs 维护的进程组信息所在的目录挂载到容器的 /proc 目录,当容器中获取 /proc 信息时,实际上获取宿主机上对该容器的进程组信息。

20201008理解:/proc 存的是当前宿主机内核运行状态的情况,比如 CPU 使用情况、内存占用率等。容器在它看来其实就是一个做了限制的进程而已,它做计算还是针对整个内核的情况。但是,容器内的实际使用情况应该是根据容器中的相关限制来得出的,比如已经对容器做了 CPU 使用的限制,那么 top 命令得到的应该是在这个限制下,容器内进程的实际使用情况。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK