CRI (容器运行时接口)详解
我们 称之为,其中最知名的就是 Docker。为了 更具扩展性, Kubernetes 1.5 版本开始就加入了。每个容器运行时都有特点,因此不少用户希望 Kubernetes 能够支持更多的容器运行时。Kubernetes从Docker 的 CRI 实现在 Kubernetes1.6 中被更新为 Beta 版本,并在 kubelet启动时默认启动。
CRI简介
Kubernetes Node (kubelet) 的主要功能就是启动和停止容器的组件,我们 称之为容器运行时 Container Runtime) ,其中最知名的就是 Docker 。为了 更具扩展性, Kubernetes 1.5 版本开始就加入了容器运行时插件 API, Container Runtime Interface, 简称 CRI。
每个容器运行时都有特点,因此不少用户希望 Kubernetes 能够支持更多的容器运行时。Kubernetes从 1.5 版本开始引入了 CRI 接口规范,通过插件接口模式,Kubernetes 无须重新编译就可以使用更多的容器运行时。
CRI 包含的组件有 Protocol Buffers、gRPC API、运行库支持及开发中的标准规范和工具。
Docker 的 CRI 实现在 Kubernetes1.6 中被更新为 Beta 版本,并在 kubelet启动时默认启动。
CRI组件(cubelet)主要实现的功能
- 镜像管理:镜像拉取、查看和移除
- pod和容器的生命周期管理,以及与容器的交互(exec/attach/port-forward)
CRI 的主要组件
kubelet 使用 gRPC 框架通过 UNIX Socket 与容器运行时 (或 RI 代理 )进行通信。在 这个过程中 kubelet 是客户端, CRI 代理 (shim) 是服务端,如图 所示:
Pod 容器的生命周期管理
Pod 由一组应用容器组成,其中包含共有的环境和资源约束,在 CRI 里,这个环境被称为 PodSandbox。
Kubernetes有意为容器运行时留下一些发挥空间,它们可以根据自己的内部实现来解释 PodSandbox。
- 对于 Hypervisor 类的运行时,PodSandbox 会具体化为一个虚拟机。
- 其他例如 Docker,会是一个 Linux 命名空间。在 vialpha1 API 中,kubelet 会创建 Pod 级别的 cgroup 传递给容器运行时,并以此运行所有进程来满足 PodSandbox对 Pod 的资源保障。
在启动 Pod 之前,kubelet调用 RuntimeService RunPodSandbox来创建环境。这一过程包括为 Pod 设置网络资源(分配IP等操作)。PodSandbox 被激活之后,就可以独立地创建、启动、停止和删除不同的容器了。kubelet 会在停止和删除 PodSandbox 之前首先停止和删除其中的容器。
kubelet 的职责在于通过 RPC 管理容器的生命周期,实现容器生命周期的钩子、存活和健康监测,以及执行 Pod 的重启策略等。
面向容器级别的设计思路
从kubernetes 架构图来分析CRI如何工作:
我们可以看到, CRI 机制能够发挥作用的核心,在于每一个容器项目现在都可以自己实现一个 CRI shim ,自行对 CRI 请求进行处理.这样, Kubernetes 就有了一个统一的容器抽象层,使得下层容器在运行的时候,可以自由地对接,从而进入 Kubernetes 当中去.
作为一个 CRI shim , container 对 CRI 的具体实现,又是怎样的呢?这个时候,我们就需要去看看 CRI 这个接口的定义里面都有什么了.
我们能够看到, CRI 待实现接口,主要有两类:
- RuntimeService .它提供的接口,主要就是和容器有关的操作.比如,创建和启动容器,删除容器,执行 exec 命令等.
- ImageService .它提供的接口,主要是和容器镜像相关的操作,比如 拉取镜像,删除镜像等等.
咱们主要来看 RuntimeService 这一部分.在这里, CRI 设计的一个重要原则,就是确保这个接口本身,只关注容器,不关注 Pod(与pod相关的是SandBox(沙箱)相关API,沙箱即容器本身,是容器而非pod的API,之所以叫PodSandbox是因为创建的沙箱(容器)用于部署pod ).之所以这样涉及,原因有两个:
- 第一, Pod 是 Kubernetes 的编排概念,而不是容器运行时的概念,所以就不能假设所有的下层容器项目,都能够暴露出可以直接映射为 Pod 的 API .
- 第二,如果 CRI 里面引入了 Pod 的概念,那么只要 Pod API 对象的字段发生变化,那么 CRI 就很有可能需要变更.
基于以上原因, CRI 设计中,并没有一个直接创建 Pod 或者启动 Pod 的接口.
Streaming API实现exec、log等功能
CRI shim 还有一个重要的工作,就是如何实现 exec , logs 等接口.这些接口不同在于, gRPC 接口调用期间, kubelet 需要和容器项目维护一个长连接来传输数据.这种 API ,就称之为 Streaming API
.
CRI shim 中对 Streaming API 的实现,依赖于一套独立的 Streaming Server 机制,如下:
备注:以上图可能画错了,api server维护着流式数据对api server的负载太大,应该是如下流程:
当对一个容器执行 kubectl exec 命令时,这个请求首先会交给 API Server , 然后 API Server 就会调用 kubelet 的 Exec API .此时, kubelet 会调用 CRI 的 Exec 接口,而负责响应这个接口的,就是 CRI shim .但是在这一步, CRI shim 并不会直接去调用后端的容器项目(比如 Docker )来进行处理,而只会返回一个 URL 给 kubelet .这个 URL ,就是该 CRI shim 对应的 Streaming Server 的地址和端口.
kubelet 在拿到这个 URL 之后,就会把它以 Redirect 的方式返回给 API Server .所以这个时候, API Server 就会通过重定向来向 Streaming Server 发起真正的 /exec 请求,和它建立长连接.
Stream Server 这一部分具体怎么实现,完全可以由 CRI shim 的维护者自行决定.
所以, CRI 这个接口的设计,实际上还是比较宽松的.这就意味着,作为容器项目的维护者,在实现 CRI 的具体接口时,往往拥有着很高的自由度,这个自由度不仅包括了容器的生命周期管理,也包括了如何将 Pod 映射成自己的实现,还包括了如何调用 CNI 插件来为 Pod 设置网络的过程.
基于此,当你对容器这一层有特殊的需求时,优先建议考虑实现一个自己的 CRI shim .
CRI 的进展
目前已经有 多款开源 RI 项目可用于 Kubernetes: Docker、CRI-O、Containerd、frakti(基于 Hypervis 的容器运行时),各 RI 运行时的安装手册可参考官网的说明。
https://blog.csdn.net/qq_20042935/article/details/125185847
https://blog.csdn.net/zll_0405/article/details/89034358
更多推荐
所有评论(0)