众所周知,软件架构只是一个模型,需要运用各种不同的技术去支撑以及实现软件架构的模型,本章节主要是描述支撑与实现Kubernetes架构所使用的技术,主要包括容器化技术、网络层技术、服务层技术、存储层技术。
由前面的章节可知,Kubernetes是一个支持插件化的集群架构,所以Kubernetes提供底层可扩展的容器运行环境接口,其目的是支持各种不同的容器运行环境,Kubernetes提供的容器运行环境接口被称之为Kubernetes CRI(Container Runtime Interface),目前Kubernetes支持containerd、CRI-O、Docker Engine、Mirantis Container Runtime以及其他实现Kubernetes CRI标准接口的容器运行环境。
Kubernetes在1.24版本之前是使用组件dockershim直接集成Docker Engine容器运行环境,在1.24版本之后,需要用户自行安装实现Kubernetes CRI标准接口的容器运行环境。
以下章节分别描述容器化涉及到的关键技术cgroups以及实现Kubernetes CRI标准接口的容器运行环境。
本章节主要描述容器化关键技术cgroups的相关内容(Linux cgroup-v2版本)。
4.1.1.1 基本定义
cgroup是control group的缩写,中文全称是控制组,cgroups表示多个控制组。
cgroup是一种机制,该机制以一种可控以及可配置的方式按层次地组织进程并且按照组织的层次分发系统的资源,包括处理器资源、内存资源以及I/O资源。
cgroup主要由两部分组成:核心部分以及控制器部分。其核心部分是负责按照层次结构组织系统的进程,控制器部分是负责按照层次结构分发指定的系统资源,也有一些工具类型的控制器是以提供服务为目的而不是分发资源的。
cgroups组织进程的层次结构形成一颗树形结构,其中一个系统进程仅对应一个cgroup,而一个进程中的所有线程都属于同一个cgroup。新创建的进程同时也被加入到父进程的cgroup中,一个进程可以从一个cgroup转移到其他cgroup中,进程的转移操作不影响子进程。
根据树形结构的约束关系,可以选择性地启动或者关闭一个cgroup中的控制器,所有控制器的行为功能也是按照层次结构的形式实行组织,如果一个cgroup中的一个控制器被开启,则会影响该cgroup的所有子层次的cgroup中的进程,如果一个嵌套cgroup中的一个控制器被开启,也会约束其资源的分发。靠近树形结构的根节点的资源约束关系不能被覆盖。
4.1.1.2 核心接口文件
本章节描述每个cgroup控制组涉及到的核心接口文件列表。
文件名称 |
文件描述 |
cgroup.type |
标识cgroup的类型包括: domain合法域 domain threaded 合法线程域的根节点 domain invalid不合法域 threaded 合法线程域 |
cgroup.procs |
保存cgroup对应的进程ID列表 |
cgroup.threads |
保存cgroup对应的线程ID列表 |
cgroup.controllers |
保存cgroup对应可开启使用的控制器列表 |
cgroup.subtree_control |
保存cgroup子层次结构中已启用的控制器列表 |
cgroup.events |
保存的键值对,populated值等于1标识子层次结构中包含存活的进程,否则值等于0 |
cgroup.max.descendants |
子层次结构中能创建cgroup的最大个数 |
cgroup.max.depth |
子层次结构中能创建cgroup的最大深度(树形结构的高度) |
cgroup.stat |
保存的键值对,nr_descendants标识子树形结构中可见的cgroup的数量,nr_dying_descendants标识子树形结构中非存活的cgroup的数量 |
4.1.1.3 基本运作
本章节主要描述cgroup基本运作的相关内容。
4.1.1.3.1 挂载
# mount -t cgroup2 none $MOUNT_POINT,该命令行格式表示挂载文件系统,其中MOUNT_POINT是文件系统的挂载点
4.1.1.3.2 进程
# mkdir $CGROUP_NAME,该命令行格式表示创建一个新创建的cgroup进程目录
# rmdir $CGROUP_NAME,该命令行格式表示删除一个不包括任何进程的cgroup进程目录
在linux操作系统中,cgroup的进程相关的目录位于:/proc/$PID/cgroup,文件中每行内容的格式0::$PATH",如果cgroup具有多个层次结构,则显示多行内容 ,每行标识一个层次结构,执行如下命令行输出如下所示:
# cat /proc/842/cgroup
0::/test-cgroup/test-cgroup-nested
如果cgroup已被删除,则显示deleted状态 ,执行如下命令行输出如下所示:
# cat /proc/842/cgroup
0::/test-cgroup/test-cgroup-nested (deleted)
4.1.1.3.3 线程
# echo threaded > cgroup.type,该命令格式表示设置cgroup的类型为线程模式,以线程作为资源粒度分发给子层次结构中的cgroup,该类型的cgroup使用线程控制器(threaded controller)实行资源分发与控制。对于以下的层次结构:
其中,子节点C是新创建的cgroup,其类型设置为domain类型的域控制器,但是此时节点B是threaded类型的线程控制器,所以,子节点C也必须转换成threaded类型的控制器才能被正常使用。节点A是threaded domain类型的控制器,是子层次结构中所有threaded类型的线程控制器的根节点。
4.1.1.3.4 事件
每一个非根节点的cgroup都包含一个cgroup.events文件,其中保存子层次结构中进程存活状态的通知信息,例如,对于以下的层次结构:
其中,ABCD分别标识不同的cgroup,其包含的层次结构关系是,B是A的子节点,C是B的子节点,D是B的子节点,括号中的值表示当前cgroup中存活进程的数量,此时,系统执行发布通知事件之后,ABC对应的cgroup.events文件中的populated值变化为1,而D的populated为0。假如,当C中的存活进程退出,则BCD对应的populated值变化为0。
4.1.1.3.5 控制器
1.开启与关闭控制器
由前一章节可知,每个cgroup对应一个cgroup.controllers接口文件,该文件中包含当前cgroup中可以开启使用的控制器列表,可以使用如下命令的方式查看:
# cat cgroup.controllers
cpu io memory
默认地,cgroup没有开启任何控制器,在cgroup.controllers控制器列表中存在的控制器才可以被开启使用。用户可以使用如下的命令开启或者关闭控制器:
# echo "+cpu +memory -io"
> cgroup.subtree_control
例如,对于以下的层次结构中,节点A开启了处理器以及内存的控制器,则节点A拥有对子节点B关于处理器以及内存资源的分发控制。同理,对于节点B开启了内存的控制器,则节点B拥有对子节点C D关于内存资源的分发控制,但是没有拥有CD关于处理器资源的分发控制,所以,CD可以对B提供的CPU资源实行自由的争夺。对资源的分发控制的意思是指B可以使用配置分别分配多少的内存空间给CD。
2.自顶向下的约束
在以上的层次结构中,假如节点A开启了处理器以及内存的控制器,则子节点B只能分发来自A节点开启的处理器以及内存的控制器,也就是,节点A中未开启的控制器,子节点B中也不能开启,子节点B只能开启节点A中拥有的控制器。假如子节点B已开启了内存的控制器,则节点A不能关闭内存的控制器。
(未完待续)