Kubernetes 源码分析之 kubelet(四)
k8s 版本 v1.18.3
CRI
CRI 是 Kubernetes 为了将容器运行时抽离出来而定义的接口。一开始 Kubernetes 是不支持 CRI 的,而是抽象了 dockershim,直接对接了 docker。然而随着容器运行时的增加(主要是当时的 rkt),频繁修改 Kubernetes 主线代码过于麻烦,因此抽象了 CRI 去对接所有的容器运行时。
kubelet 通过 gRPC 和实现了 CRI 的进程交互,以达到解耦合的目的。
CRI 中的 gRPC 服务定义了以下几个 interface
(一) RuntimeService,容器运行时相关的操作
- RuntimeVersioner,获取版本相关信息 
- ContainerManager,定义了各种 container 相关操作 
- PodSandboxManager,定义了各种 pod 相关的操作 
- ContainerStatsManager,定义了 container 的 cpu,memory 之类的 stats 
(二) ImageManagerService,容器镜像相关的操作
CRI 的具体定义可以查看 staging/src/k8s.io/cri-api/pkg/apis 下的代码。
dockershim
dockershim 是 Kubernetes 内置的 CRI 实现,用于隔离和 docker 相关的操作,dockershim 的代码定义在 pkg/kubelet/dockershim 下。
Kubernetes 1.20 版本后,dockershim 将会被废弃。
cri-o
cri-o 是一个实现了 CRI 接口的项目,用于和符合 OCI 标准的容器运行时对接。

整个 cri-o 由以下几个部分组成

- OCI compatible runtime 
- containers/storage 
- containers/image 
- networking (CNI) 
- container monitoring (conmon) 
- security is provided by several core Linux capabilities 
OCI(Open Container Initiative) 是开放容器标准,定义了容器相关的一系列标准

- runtime-spec 
- image-spec 
- distribution-spec 
OCI runtime spec 中定义了一些容器相关的操作

1. state 
2. create 
3. start 
4. kill 
5. delete 
同时还有一些容器相关的 hooks

- prestart 
- createRuntime 
- createContainer 
- startContainer 
- poststart 
- poststop 
整个容器的生命周期如下

- create 命令被调用 
- 容器的运行时环境将根据 config.json 被创建,此时用户进程未运行 
- prestart hook 被调用,如果 hook 失败了,停止容器,跳转到第 12 步 
- createRuntime hook 被调用,如果 hook 失败了,停止容器,跳转到第 12 步 
- createContainer hook 被调用,如果 hook 失败了,停止容器,跳转到第 12 步 
- start 命令被调用 
- startContainer hook 被调用,如果 hook 失败了,停止容器,跳转到第 12 步 
- runtime 运行用户进程 
- poststart hook 被调用,如果 hook 失败了,打 warning 日志,继续运行 
- 进程退出 
- delete 命令被调用 
- 容器被销毁 
- poststop hook 被调用,如果 hook 失败了,打 warning 日志,继续运行 
一系列项目
- runc 是 OCI runtime 的默认实现 
- containerd 是 docker 剥离出来的容器相关的 runtime 实现,containerd 也使用了 runc 作为 OCI runtime。本来 containerd 有个 CRI 实现 containerd/cri,不过在 2020.10 月已经被合入 containerd 主 repo 了 
- cri-o 实现了 CRI 并且能够以符合 OCI 标准 的 runtime 作为底层实现,是 CRI 和 OCI 的中间层 
- crun 另一个用 C 写的 OCI runtime,之所以有这样一个项目是因为 runc 有些比较 hack 的操作(会调用自己),然后还直接调用了 C 代码 
最后
- 为什么需要定时触发 - syncCh
- 为什么需要 - housekeeping
- containerManager 以及 pod 的 cgroups 结构 
- volumeManager 以及 CSI 
- CNI 

敬请期待 Kubernetes 源码分析之 kubelet(五)
 点击屏末 | 阅读原文 | 即刻学习
 点击屏末 | 阅读原文 | 即刻学习