前提
最近在看容器化的一些书,主要是基于cgroup和namespace的,当然最主要的是cgroup,基于这个能力,我们才拥有了容器化的能力。
cgroup
我先来看一下kernel中的定义:
cgroup is a mechanism to organize processes hierarchically and distribute system resources along the hierarchy in a controlled and configurable manner.
cgroup 是一个机制,用于组织进程的层次结构,并根据层次结构在可配置和可控制的方式分配系统资源。
cgroup is largely composed of two parts - the core and controllers. cgroup core is primarily responsible for hierarchically organizing processes. A cgroup controller is usually responsible for distributing a specific type of system resource along the hierarchy although there are utility controllers which serve purposes other than resource distribution.
cgroup 主要由两部分组成:核心和控制器。 cgroup 核心主要负责进程的层次组织。 控制器通常负责沿着层次结构分配特定类型的系统资源,尽管还有其他控制器,它们提供除资源分配之外的用途。
cgroups form a tree structure and every process in the system belongs to one and only one cgroup. All threads of a process belong to the same cgroup. On creation, all processes are put in the cgroup that the parent process belongs to at the time. A process can be migrated to another cgroup. Migration of a process doesn’t affect already existing descendant processes.
cgroups 形成一个树状结构,系统中所有进程都属于一个且只有一个 cgroup。 进程的所有线程都属于同一个 cgroup。 创建时,所有进程都放在父进程所属的 cgroup 中。 进程可以迁移到另一个 cgroup。 进程的迁移不会影响已经存在的子进程。
Following certain structural constraints, controllers may be enabled or disabled selectively on a cgroup. All controller behaviors are hierarchical - if a controller is enabled on a cgroup, it affects all processes which belong to the cgroups consisting the inclusive sub-hierarchy of the cgroup. When a controller is enabled on a nested cgroup, it always restricts the resource distribution further. The restrictions set closer to the root in the hierarchy can not be overridden from further away.
按照某些结构约束,可以在 cgroup 上有选择地启用或禁用控制器。 所有控制器行为都是层次结构的 - 如果在一个控制器上启用一个控制器,它会影响属于该控制器所包含的子层次结构的所有进程。 当在一个嵌套的 cgroup 上启用一个控制器时,它总是进一步限制资源分配。 层次结构中更接近根部的限制不能被更远的层次结构覆盖。
简单来说就是用来分配资源给进程,并且可以灵活配置。
实现
cgroup 的实现主要分为两部分:
- 内核部分
- 用户空间部分
现有的版本主要是cgroup-v1和cgroup-v2版本,v2改善了多个根层级的问题,这个我们后面再讲,留个坑位
docker和k8s中的应用
驱动
内核中主要是实现了:cgroupfs、systemd cgroup这两个cgroup的驱动,其中cgroupfs较老,systemd cgroup较新,大多数的发行版都是采用systemd cgroup,比如:arch(介绍Cgroup),主要原因是流行的发行版都是使用systemd引导启动,核心就是实现了cgroup,这块留个坑位,以后聊一聊systemd
docker与kubernetes
先说docker,docker默认使用的cgroupfs驱动,k8s中在1.22之前默认的是cgroupfs,但是之后就默认为systemd了,这也是拥抱了未来
systemd
cgroupfs驱动的相关内容已经不太好搜到了且已经有点过时了,我们直接来了解一下systemd cgroup怎么实现的驱动。因为cgroup本身是kernel自带的内容,所以其实到头来我们就是写配置文件,接下来kernel(调用cgroups-v2能力)将会读取到对应的文件,实现资源隔离,具体关注的文件如下:
/sys/fs/cgroup/
主要就是关注这个文件夹下的文件,比如我们创建:
/sys/fs/cgroup/Example/
cgroups-v2会直接在这个文件夹下创建cgroup的相关文件:
ll /sys/fs/cgroup/Example/
-r—r—r--. 1 root root 0 Jun 1 10:33 cgroup.controllers
-r—r—r--. 1 root root 0 Jun 1 10:33 cgroup.events
-rw-r—r--. 1 root root 0 Jun 1 10:33 cgroup.freeze
-rw-r—r--. 1 root root 0 Jun 1 10:33 cgroup.procs
…
-rw-r—r--. 1 root root 0 Jun 1 10:33 cgroup.subtree_control
-r—r—r--. 1 root root 0 Jun 1 10:33 memory.events.local
-rw-r—r--. 1 root root 0 Jun 1 10:33 memory.high
-rw-r—r--. 1 root root 0 Jun 1 10:33 memory.low
…
-r—r—r--. 1 root root 0 Jun 1 10:33 pids.current
-r—r—r--. 1 root root 0 Jun 1 10:33 pids.events
-rw-r—r--. 1 root root 0 Jun 1 10:33 pids.max