上一篇文章中,讲解了Docker run的具体流程以及Docker是如何改变PID为1的底层原理。
具体文章可见《Docker就应该这么学-06》
有需要的小伙伴可以回顾一下。
接下来本文会详细介绍一下Docker 是如何增加容器的资源限制
增加容器的资源限制
获取代码
git clone https://gitee.com/mjreams/docker.git
上一节中,已经可以通过命令行 docker run -ti
的方式创建并启动容器。这一节,将通过cgroup对容器的资源进行控制。
# 这一节中,将实现通过以下命令的方式控制容器的内存和CPU配置。
docker run -ti -m I00m -cpuset 1 -cpushare 512 /bin/sh
定义Cgroups数据结构
前几篇中,对Cgroups包含的3个概念进行了介绍,这里做如下简单回顾。
-
• cgroup hierarchy中的节点,用于管理进程和subsystem的控制关系。
-
• subsystem作用于hierarchy上的cgroup节点,并控制节点中进程的资源占用。
-
• hierarchy将cgroup通过树状结构串起来,并通过虚拟文件系统的方式暴露给用户。
根据上面3个概念的关系,先创建出如下的数据结构。
见cgroups/subsystems/subsystem.go
上面定义了subsystem的模型,下面以memory的subsystem为例介绍 一 下要怎么实现 subsystem 的操作。
见cgroups/subsystems/memory.go
上面以memory的subsystem为例,介绍了如何实现subsystem的cgroup资源限制。其中,GetCgroupPath函数是找到对应subsystem挂载的hierarchy相对路径对应的cgroup在虚拟文件系统中的路径,然后通过这个目录的读写去操作cgroup。那么,是如何找到挂载了subsystem的hierarchy的挂载目录的呢?先来熟悉下/proc/{pid}/mountinfo
文件,如下。
通过/proc/self/mountinfo,可以找出与当前进程相关的mount信息。在前文中,我们讲过Cgroups的hierarchy的虚拟文件系统是通过cgroup类型文件系统的mount挂载上去的,option中加上subsystem,代表挂载的subsystem类型,这样就可以在mountinfo中找到对应的subsystem的挂载目录了,比如memory。
30 27 0:24 I /sys/fs/cgroup/rnernory rw , nosuid, nodev , noexec , relatirne shared : l3 - cgroup cgroup rw , rnernory
通过最后的option是rw,memory,可以看出这一条挂载的subsystem是memory,那么在/sys/fs/cgroup/memory中创建文件夹对应创建的cgroup,就可以用来做内存的限制,实现如下。
见cgroups/subsystems/utils.go
最后,需要把这些不同subsystem中的cgroup管理起来,并与容器建立关系。
见cgroups/cgroup_manager.go
通过 CgroupManager,将资源限制的配置,以及将进程移动到 cgroup 中的操作交给各个 subsystem 去处理。
如下,用一张流程图来展示下上各个组件之间的调用关系。
CgroupManager 在配置容器资源限制时,首先会初始化 Subsystem 的实例, 然后遍历调用 Subsystem 实例的 Set 方法,创建和配置不同 Subsystem 挂载的 hierarchy 中的 cgroup,最后再通过调用 Subsystem 实例将容器的进程分别加入到那些 cgroup 中,实现容器的 资源限制 。