文章目录

  • 前言
  • Linux Cgroups
  • Cgroups 存在的问题
  • 总结


前言

在上一篇文章中我已经介绍了 Linux 容器实现隔离的手段 – Namespace。Namespace 技术实际上修改了应用进程看待整个计算机视图,即它的视线被操作系统做了限制,只能看到某些指定的内容。但其实对宿主机来说,这些隔离了的进程与其他进程并无多大区别。

在介绍完隔离技术后,我们再来介绍一下容器的限制技术。

Linux Cgroups

也许你会问,我们不是通过 Linux Namespace 创建了一个容器了嘛,为什么还是需要对容器做限制呢?

我们可以这么想,虽然容器内的第 1 号进程在障眼法的干扰下只能看到容器里的情况,但是宿主机上,它作为第 100 号进程与其他所有进程之间依然是平等的竞争关系。这就意味着,虽然第 100 号进程表面上被隔离了起来,但是它所能够使用到的资源(比如 CPU、内存),却是可以随时被宿主机上的其他进程(或者其他容器)占用的。当然,这个 100 号进程自己也可能把所有资源吃光。这些情况,显然都不是一个沙盒应该表现出来的合理行为。

所以,我们应该对此加以限制,而 Linux Cgroups 就是 Linux 内核中用来为进程设置资源限制的一个重要功能。

Linux Cgroups 的全称是 Linux Control Group。它最主要的作用,就是限制一个进程组能够使用的资源上限,包括 CPU、内存、磁盘、网络带宽等等。

在 Linux 中,Cgroups 给用户暴露出来的操作接口是文件系统,即它以文件和目录的方式组织在操作系统的 /sys/fs/cgroup 路径下。在 /sys/fs/cgroup 下面有很多诸如 cpuset、cpu、 memory 这样的子目录,也叫子系统。这些都是我这台机器当前可以被 Cgroups 进行限制的资源种类。Cgroups 的每一个子系统都有其独有的资源限制能力,比如:

  1. cpu:限制进程在一段时间内能够分配到的 CPU 时间
  2. blkio:为块设备设定 I/O 限制,一般用于磁盘等设备
  3. cpuset:为进程分配单独的 CPU 核和对应的内存节点
  4. memory:为进程设定内存使用的限制

我们可以把 Linux Cgroups 理解成一个子系统目录加上一组资源限制文件的组合。而对于 Docker 等 Linux 容器项目来说,它们只需要在每个子系统下面,为每个容器创建一个控制组(即创建一个新目录),然后在启动容器进程之后,把这个进程的 PID 填写到对应控制组的 tasks 文件中就可以了。而至于在这些控制组下面的资源文件里填上什么值,就靠用户执行 docker run 时的参数指定了。

Cgroups 存在的问题

跟 Namespace 的情况类似,Cgroups 对资源的限制能力也有很多不完善的地方,被提及最多的自然是 /proc 文件系统的问题。

我们知道,Linux 下的 /proc 目录存储的是记录当前内核运行状态的一系列特殊文件,用户可以通过访问这些文件,查看系统以及当前正在运行的进程的信息,比如 CPU 使用情况、内存占用率等,这些文件也是 top 指令查看系统信息的主要数据来源。

但是,你如果在容器里执行 top 指令,就会发现,它显示的信息居然是宿主机的 CPU 和内存数据,而不是当前容器的数据。造成这个问题的原因就是,/proc 文件系统并不知道用户通过 Cgroups 给这个容器做了什么样的资源限制,即:/proc 文件系统不了解 Cgroups 限制的存在。

总结

一个正在运行的 Docker 容器,其实就是一个启用了多个 Linux Namespace 的应用进程,而这个进程能够使用的资源量,则受 Cgroups 配置的限制。