2008年,最早的容器运行时LXC(Linux Container)诞生。2013年,Docker容器引擎发布。Docker开发之初尝试使用LXC,但由于彼时LXC隔离性相对较差,因此Docker开发Libcontainer,最终形成runC。2014年Kubernetes发布时,由于社区中Docker已经被大量使用,因此就用Docker容器引擎。
随着Docker越来越重,CoreOS以rkt的形式发布了一个更简单的独立运行时。rkt与Kubernetes具有较好的协同工作性。
随着容器运行时格式的增加,2015年6月OCI(Open Containers Initiative)项目成立。这个项目的目的是对容器运行时的接口标准化,runC在第一时间通过了OCI标准的认证。
为了实现Kubernetes与容器运行时解耦,Google提出了CRI(Container Runtime Interface)标准。它是一组Kubernetes与Container Runtime进行交互的接口,这使Kubernetes用户可以插入除Docker之外的其他容器引擎。所以说,CRI和OCI并不冲突:Kubernetes定义的是它调用容器运行时的标准接口,OCI定义的是容器运行时本身的标准。
容器运行时接口(OCI)标准提出以后,红帽考虑到Kubernetes在企业中的应用,专门为Kubernetes做了一个轻量级的容器运行时,决定重用了runC等基本组件来启动容器,并实现了一个最小的CRI称为CRI-O,CRI-O是CRI的一种标准实现。2017年10月,CRI-O正式发布。
当红帽开发CRI-O时,Docker也在研究CRI标准,这导致了另一个名为Containerd的运行时的出现(实际上它是从Docker Engine剥离出来的)。所以从1.12版本开始,Docker会多一层Containerd组件。Kubernetes将Containerd接入CRI的标准中。即cri-containerd。
从概念上,从PaaS顶层到底层的调用关系是:
Orchestration API→Container Engine API→Kernel API
旧版本的PaaS平台(如OpenShift 3)的调用架构:
Kubernetes Master→Kubelet→Docker Engine→Containerd→runC→Linux Kernel
红帽OpenShift最新的调用架构:
Kubernetes Master→Kubelet→CRI-O→runC→Linux kernel
详细的调用架构如图2-1所示。
图2-1 Kubernetes与CRI-O调用架构
我们看到,采用CRI-O运行时OpenShift对底层的调用链路更短、效率更高、稳定性更强。而很重要的一点是CRI-O的运行不依赖于守护进程,也就是说,即使OpenShift节点上的CRI-O的Systemd进程终止,所有运行的Pod也不受影响,具体的验证步骤可以参照“大魏分享”公众号文章,如图2-2所示。
图2-2 验证CRI-O在故障下的表现
在介绍了容器发展史后,接下来我们介绍OpenShift的发展史以及与Kubernetes的关系。