自 Docker 开启了使用容器的爆发式增长,有越来越多的工具和标准来帮助管理和使用这项容器化技术,与此同时也造成了有很多术语让人感到困惑。
容器生态系统
容器生态系统是由许多令人兴奋的技术、大量的专业术语和大公司相互争斗组成的。
幸运的是,这些公司偶尔会在休战中走到一起合作,商定一些标准,这些标准有助于使这个生态系统在不同的平台和操作系统之间更具互操作性,并减少对单一公司或项目的依赖。
这张图显示了 Docker、Kubernetes、CRI、OCI、containerd 和 runc 在这个生态系统中是如何结合的。
其工作流程简单来说是这样的:
- Docker,Kubernetes 等工具来运行一个容器时会调用容器运行时(CRI)比如 containerd,CRI-O
- 通过容器运行时来完成容器的创建、运行、销毁等实际工作
- Docker 使用的是 containerd 作为其运行时;Kubernetes 支持 containerd,CRI-O 等多种容器运行时
- 这些容器运行时都遵循了 OCI 规范,并通过 runc 来实现与操作系统内核交互来完成容器的创建和运行
下面就分别介绍图中所提到的术语和规范。
Docker
首先我们从大家都很熟悉的 Docker 开始,因为它是管理容器的最流行的工具。对很多人来说"Docker"这个名字本身就是"容器"的代名词。
Docker 启动了整个容器的革命,它创造了一个很好用的工具来处理容器也叫 Docker,这里最主要的要明白:
- Docker 并不是这个唯一的容器竞争者
- 容器也不再与 Docker 这个名字紧密联系在一起
目前的容器工具中,Docker 只是其中之一,其他著名的容器工具还包括:Podman[1],LXC[2],containerd[3],Buildah[4] 等。
因此,如果你认为容器只是关于 Docker 的,那是片面的不对的。
Docker 组成
Docker 可以轻松地构建容器镜像,从 Docker Hub 中拉取镜像,创建、启动和管理容器。实际上,当你用 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 的直接支持,而倾向于只使用实现其容器运行时接口的容器运行时,这可能意味着使用 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 通过其 CRI 插件实现了 Kubernetes 容器运行时接口(CRI),它可以管理容器的整个生命周期,包括从镜像的传输、存储到容器的执行、监控再到网络。