早期的Kubernetes的Runtime架构比较简单,创建容器时kubelet直接调用docker daemon,docker daemon调用自己的libcontainer就把容器运行起来。后来 coreos的rkt也要做Kubernetes的Runtime,kubernetes也开发了接口去支持rkt。
于是就有了这个样子:
这样下去Runtime会越来越多, Runtime的适配工作将越来越大,于是Kubernetes推出了 CRI(Container Runtime Interface) ,即容器运行时接口(Container Runtime Interface)。这样Kubernetes 提供Runtime标准接口,谁的Runtime想进来就按照它的标准来实现,Kubernetes不进行适配开发,将工作量推给了Runtime厂家。
标准不是谁都可以推的,以Kubernetes当时的影响力,Runtime厂家不会主动提供 CRI 接口以绑定kubernetes,于是就有了 shim(垫片)这个东西,每个shim 的职责就是作为 Adapter 将各种容器运行时本身的接口适配到 Kubernetes 的 CRI 接口上。
于是就有了这个样子:
shim(垫片)只是临时的过渡,随着Kubernetes逐渐成为容器技术事实上的标准, containerd和CRI-O也已经完全符合CRI接口标准了, Dockershim 在 v1.20版本被从 Kubelet 中移除,意味着取消了对 Docker 作为容器运行时的直接支持,因为 Docker 并不符合CRI,如果符合的话,当时就不需要这个 shim了。
于是就有了这个样子:
这里要提到两个重要的标准:CRI和OCI
CRI简介
CRI(Container Runtime Interface)是Kubernetes定义的一组与contianer runtime进行交互的接口,用于将Kubernetes平台与特定的容器实现解耦。
OCI简介
OCI(Open Container Initiative)提出了明确的容器运行时和镜像规范,它是容器运行时的底层。 创建容器需要做一些设置 namespaces和 cgroup,挂载 root filesystem 等操作,而OCI就是规范这些底层操作的。OCI的一个参考实现叫做 runC。
简单总结起来就是:
上面有CRI标准,下面有OCI标准,按照CRI接口标准实现CRI-Runtime,按照OCI标准实现OCI-Runtime。
目前可以找到很多两者的实现:
符合CRI标准的CRI-Runtime:
Docker(借助 dockershim),containerD(借助 CRI-containerd),CRI-O,Frakti。
符合OCI标准的OCI-Runtime:
runC,Kata(以及它的前身 runV 和 Clear Containers),gVisor,railcar。
在kubernetes看来,调度框架位于容器生态系统的中心位置,而“引擎”其实只是一个工具。