Docker,containerd,CRI,CRI-O,OCI,runc 分不清?
转载自Docker,containerd,CRI,CRI-O,OCI,runc 分不清?看这一篇就够了 - 知乎 (zhihu.com)
容器的生态系统
容器生态系统是由许多令人兴奋的技术、大量的专业术语和大公司相互争斗组成的。
幸运的是,这些公司偶尔会在休战中走到一起合作,商定一些标准,这些标准有助于使这个生态系统在不同的平台和操作系统之间更具互操作性,并减少对单一公司或项目的依赖。
这张图显示了 Docker、Kubernetes、CRI、OCI、containerd 和 runc 在这个生态系统中是如何结合的。
其工作流程简单来说是这样的
- Docker:Kubernetes等工具来运行一个容器时会调用容器运行时CRI比如containerd,CRI-O
- 通过容器运行时来完成容器的创建、运行、销毁等时机工作
- Docker使用的是containerd作为容器运行时,Kubernetes支持containerd,CRO-O等容器运行时
- 这些容器运行时都遵循了OCI规范,通过runc来实现与操作系统内核交互来完成容器的创建和运行
docker
首先我们从大家都很熟悉的 Docker 开始,因为它是管理容器的最流行的工具。对很多人来说"Docker"这个名字本身就是"容器"的代名词。
Docker 启动了整个容器的革命,它创造了一个很好用的工具来处理容器也叫 Docker,这里最主要的要明白:
- Docker并不是这个唯一的容器竞争者
- 容器也不再与Docker这个名字紧密联系在一起
目前的容器工具中,Dcoker只是其中之一,其他注明的容器还包括Podman,LXC,containerd,Buildah等
因此,如果你认为容器只是关于 Docker 的,那是片面的不对的。
Docker组成
docker可以轻松构建容器镜像,从DockerHub中拉取镜像,创建、启动和管理容器。实际上,当你用Docker运行一个容器实际上是通过Docker守护程序,containerd和runc来运行他
为了实现这一切docker是由这些项目组成(还有其他项目,但这些项目是主要的)。
- docker-cli:这是一个命令行工具,它是用来完成docker pull,build,run,exec等命令进行交互。
- containerd:这是一个管理和运行容器的守护进程。它推送和拉动镜像,管理存储和网络,并监督容器运行。
- runc:这是低级别的容器运行时间(实际创建和运行容器的东西)。它包括一个libcontainer,一个英语创建容器的基于Go的本地实现。
Docker镜像
许多人说的Docker镜像,实际上是一Open container Initiative(OCI)格式打包的镜像。
因此如果你从Docker Hub或其他注册中心拉出一个镜像,你应该能够用docker命令使用它,或者在Kubernetes几群上使用,或用podman工具以及任何其他支持OCI镜像格式规范的工具。
Dockershim
在Kubernetes包括一个名为dockershim的组件,使它能够支持Docker。但Docker由于比Kubernetes更早,没有实现CRI,所以这就是dockershim存在的原因,它支持将Docker被硬编码到Kubernetes中。随着容器化称为行业标准,Kubernetes项目增加了对额外运行时的支持,比如通过 Container Runtime Interface (CRI) 容器运行时接口来支持运行容器。因此dockershim称为了Kubernetes中的一个异类,对Docker和dockershim的依赖已经渗透到了CNCF生态中的各种工具和项目中,导致代码脆弱。
2022 年 4 月 dockershim 将会从 Kubernetes 1.24 中完全移除。今后 Kubernetes 将取消对 Docker 的直接支持,而倾向于只使用实现容器运行时接口(CRI)的容器运行时,这可能意味着使用containerd或CRI-O。这并不意味着Kubernetes将不能运行Docker格式的容器。containerd和CRI-O都可以运行Docker格式(实际上是OCI格式)的镜像,他们只是无法使用Docker命令或Docker守护程序。
Container Runtime Interface (CRI)
CRI(容器运行时接口)是Kubernetes用来控制创建和管理容器不同运行时的API,它使Kubernetes更容易使用不同的容器运行时。它是一个插件接口,这意味着任何符合该标准的实现的容器都可以被Kubernetes使用。
Kubernetes 项目不必手动添加对每个运行时的支持,CRI API 描述了 Kubernetes 如何与每个运行时进行交互,由运行时决定如何实际管理容器,因此只要它遵守 CRI 的 API 即可。
你可以使用你喜欢的containerd来运行你的容器,也可以使用CRI-O来运行你的容器,因为这俩者都实现了CRI规范。
Containerd
containerd是一个来自Docker的高级容器运行时,并实现了CRI规范。它是从Docker项目中分离出来,之后containerd被捐赠给CNCF为容器社区提供创新容器解决方案的基础。
所以Docker自己在内部使用containerd,当你安装docker时也会安装containerd。
containerd通过其插件实现了Kubernetes容器运行时接口(CRI),它可以管理容器的整个生命周期,包括从镜像的传输、存储到容器的执行、监控再到网络。
CRI-O
CRI-O是另一个实现了容器运行时接口CRI的高级别容器运行时,可以使用OCI开放容器倡议兼容的运行时,它是containerd的一个替代品。
CRI-O 诞生于 RedHat、IBM、英特尔、SUSE、Hyper 等公司。它是专门从头开始创建的,作为 Kubernetes 的一个容器运行时,它提供了启动、停止和重启容器的能力,就像 containerd 一样。
Open Container Initiative(OCI)
OCI 开放容器倡议,是一个由科技公司组成的团体,其目的是围绕容器镜像和运行时创建开放的行业标准。他们维护容器镜像格式的规范,以及容器应该如何运行。
OCI 背后的想法是,你可以选择符合规范的不同运行时,这些运行时都有不同的底层实现。
例如,你可能有一个符合 OCI 的运行时用于你的 Linux 主机,另一个用于你的 Windows 主机。这就是拥有一个可以由许多不同项目实施的标准的好处。这种同样的 "一个标准,多种实现" 的方法其实还有很多都在使用,从蓝牙设备到 Java APIs。
runc
runc是轻量级的通用运行时容器,它遵循OCI规范,是实现OCI接口的最低级别组件,它与内核交互创建并运行容器。
runc为容器提供了所有低级功能,与现有的低级Linux功能交互,如命名空间和控制组,它使用这些功能来创建和运行容器进程。
runc 的几个替代品:
- crun [5]一个用 C 语言编写的容器运行时(相比之下,runc 是用Go编写的。)
- 来自 Katacontainers 项目的 kata-runtime [6] 它将 OCI 规范实现为单独的轻量级虚拟机(硬件虚拟化)。
- Google 的 gVisor [7],它创建了拥有自己内核的容器。它在其运行时中实现了 OCI,称为 runsc。
runc 是一个在 Linux 上运行容器的工具,所以这意味着它可以在 Linux 上、裸机上或虚拟机内运行。
在 Windows 上,它略有不同,与 runc 相当的是微软的主机计算服务(HCS),它包括一个叫 runhcs [8] 的工具,它本身是 runc 的一个分叉,也实现了开放容器倡议的规范。
总结
在本篇中,我们看到 Docker 只是容器生态系统中的一个小部分。另外还有一堆开放的标准,这就使得不同的实现互相之间是可替换的。
这就是为什么有 CRI 和 OCI 标准,以及 containerd、runc 和 CRI-O 等项目存在的原因了。
现在你知道了关于容器这个有趣而又略显复杂的世界的一切,下次和别人讨论时,不要说你在使用 "Docker 容器" : )
The differences between Docker, containerd, CRI-O and runc [9]