containerd 1.0 探索之旅
containerd 被用于 Docker、Kubernetes CRI、以及一些其它的项目，在这些平台中事实上都使用了 containerd，而许多人并不知道 containerd 存在于这些平台之中，这篇文章就是为这些人所写的。
containerd 被用于 Docker、Kubernetes CRI、以及一些其它的项目，在这些平台中事实上都使用了 containerd，而许多人并不知道 containerd 存在于这些平台之中，这篇文章就是为这些人所写的。
![](/data/attachment/album/201802/22/124722gibtz0ag72azo442.jpg)


我们在过去的文章中讨论了一些 containerd 的不同特性，它是如何设计的，以及随着时间推移已经修复的一些问题。containerd 被用于 Docker、Kubernetes CRI、以及一些其它的项目，在这些平台中事实上都使用了 containerd，而许多人并不知道 containerd 存在于这些平台之中，这篇文章就是为这些人所写的。我将来会写更多的关于 containerd 的设计以及特性集方面的文章，但是现在，让我们从它的基础知识开始。


![](/data/attachment/album/201802/22/124733dmzlyg59eg0i3rmh.jpg)


我认为容器生态系统有时候可能很复杂。尤其是我们所使用的术语。它是什么？一个运行时，还是别的？一个运行时 … containerd（它的发音是 “container-dee”）正如它的名字，它是一个容器守护进程，而不是一些人忽悠我的“<ruby> 收集 <rt>  contain </rt></ruby><ruby> 迷 <rt>  nerd </rt></ruby>”。它最初是作为 OCI 运行时（就像 runc 一样）的集成点而构建的，在过去的六个月中它增加了许多特性，使其达到了像 Docker 这样的现代容器平台以及像 Kubernetes 这样的编排平台的需求。


那么，你使用 containerd 能去做些什么呢？你可以拥有推送或拉取功能以及镜像管理。可以拥有容器生命周期 API 去创建、运行、以及管理容器和它们的任务。一个完整的专门用于快照管理的 API，以及一个其所依赖的开放治理的项目。如果你需要去构建一个容器平台，基本上你不需要去处理任何底层操作系统细节方面的事情。我认为关于 containerd 中最重要的部分是，它有一个版本化的并且有 bug 修复和安全补丁的稳定 API。


![](/data/attachment/album/201802/22/124741loyjfe3oyqbew3la.jpg)


由于在内核中没有一个 Linux 容器这样的东西，因此容器是多种内核特性捆绑在一起而成的，当你构建一个大型平台或者分布式系统时，你需要在你的管理代码和系统调用之间构建一个抽象层，然后将这些特性捆绑粘接在一起去运行一个容器。而这个抽象层就是 containerd 的所在之处。它为稳定类型的平台层提供了一个客户端，这样平台可以构建在顶部而无需进入到内核级。因此，可以让使用容器、任务、和快照类型的工作相比通过管理调用去 clone() 或者 mount() 要友好的多。与灵活性相平衡，直接与运行时或者宿主机交互，这些对象避免了常规的高级抽象所带来的性能牺牲。结果是简单的任务很容易完成，而困难的任务也变得更有可能完成。


![containerd](/data/attachment/album/201802/22/125521kllr1slfonf58qd2.jpg)


containerd 被设计用于 Docker 和 Kubernetes、以及想去抽象出系统调用或者在 Linux、Windows、Solaris 以及其它的操作系统上特定的功能去运行容器的其它容器系统。考虑到这些用户的想法，我们希望确保 containerd 只拥有它们所需要的东西，而没有它们不希望的东西。事实上这是不太可能的，但是至少我们想去尝试一下。虽然网络不在 containerd 的范围之内，它并不能做成让高级系统可以完全控制的东西。原因是，当你构建一个分布式系统时，网络是非常中心的地方。现在，对于 SDN 和服务发现，相比于在 Linux 上抽象出 netlink 调用，网络是更特殊的平台。大多数新的网络都是基于路由的，并且每次一个新的容器被创建或者删除时，都会请求更新路由表。服务发现、DNS 等等都需要及时被通知到这些改变。如果在 containerd 中添加对网络的管理，为了能够支持不同的网络接口、钩子、以及集成点，将会在 containerd 中增加很大的一块代码。而我们的选择是，在 containerd 中做一个健壮的事件系统，以便于多个消费者可以去订阅它们所关心的事件。我们也公开发布了一个 [任务 API](https://github.com/containerd/containerd/blob/master/api/services/tasks/v1/tasks.proto)，它可以让用户去创建一个运行任务，也可以在一个容器的网络命名空间中添加一个接口，以及在一个容器的生命周期中的任何时候，无需复杂的钩子来启用容器的进程。


在过去的几个月中另一个添加到 containerd 中的领域是完整的存储，以及支持 OCI 和 Docker 镜像格式的分布式系统。有了一个跨 containerd API 的完整的目录地址存储系统，它不仅适用于镜像，也适用于元数据、检查点、以及附加到容器的任何数据。


我们也花时间去 [重新考虑如何使用 “图驱动” 工作](https://blog.mobyproject.org/where-are-containerds-graph-drivers-145fc9b7255)。这些是叠加的或者允许镜像分层的块级文件系统，可以使你执行的构建更加高效。当我们添加对 devicemapper 的支持时，<ruby> 图驱动 <rt>  graphdrivers </rt></ruby>最初是由 Solomon 和我写的。Docker 在那个时候仅支持 AUFS，因此我们在叠加文件系统之后，对图驱动进行了建模。但是，做一个像 devicemapper/lvm 这样的块级文件系统，就如同一个堆叠文件系统一样，从长远来看是非常困难的。这些接口必须基于时间的推移进行扩展，以支持我们最初认为并不需要的那些不同的特性。对于 containerd，我们使用了一个不同的方法，像快照一样做一个堆叠文件系统而不是相反。这样做起来更容易，因为堆叠文件系统比起像 BTRFS、ZFS 以及 devicemapper 这样的快照文件系统提供了更好的灵活性。因为这些文件系统没有严格的父/子关系。这有助于我们去构建出 [快照的一个小型接口](https://github.com/containerd/containerd/blob/master/api/services/snapshots/v1/snapshots.proto)，同时还能满足 [构建者](https://blog.mobyproject.org/introducing-buildkit-17e056cc5317) 的要求，还能减少了需要的代码数量，从长远来看这样更易于维护。


![](/data/attachment/album/201802/22/125526ewawwyyyywtvl7gl.jpg)


你可以在 [Stephen Day 2017/12/7 在 KubeCon SIG Node 上的演讲](https://speakerdeck.com/stevvooe/whats-happening-with-containerd-and-the-cri)找到更多关于 containerd 的架构方面的详细资料。


除了在 1.0 代码库中的技术和设计上的更改之外，我们也将 [containerd 管理模式从长期 BDFL 模式转换为技术委员会](https://github.com/containerd/containerd/pull/1748)，为社区提供一个独立的可信任的第三方资源。




---


via: <https://blog.docker.com/2017/12/containerd-ga-features-2/>


作者：[Michael Crosby](https://blog.docker.com/author/michael/) 译者：[qhwdw](https://github.com/qhwdw) 校对：[wxy](https://github.com/wxy)


本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译，[Linux中国](https://linux.cn/) 荣誉推出

