为什么Kubernetes不使用libnetwork

自1.0版发布以来,Kubernetes拥有非常基本的网络插件形式-与Docker的大约相同时间 lib网络 和容器网络模型(CNM) was introduced. Unlike lib网络, the Kubernetes plugin system still retains its "α"指定。现在已经发布并支持了Docker的网络插件支持,我们得到一个明显的问题是为什么Kubernetes尚未采用它。毕竟,供应商几乎肯定会为Docker编写插件-我们最好使用相同的驱动程序,对吗?

在继续之前,重要的是要记住Kubernetes是一个支持多个容器运行时的系统,而Docker只是其中之一。配置网络是每个运行时的一个方面,因此当人们问“ Kubernetes是否支持CNM?”时,它们的真正含义是“ kubernetes是否将在Docker运行时中支持CNM驱动程序?”如果我们能在运行时中获得通用的网络支持,那将是很好,但这不是一个明确的目标。

实际上,Kubernetes尚未在Docker运行时中采用CNM / lib网络。实际上,我们一直在研究替代的容器网络接口(CNI)模型,由CoreOS提出,并且是应用容器( 应用程序)规范。为什么?有多种原因,包括技术原因和非技术原因。

首先,Docker网络驱动程序的设计中有一些基本假设会给我们带来麻烦。

Docker具有“本地”和“全局”驱动程序的概念。本地驱动程序(例如“网桥”)以机器为中心,并且不进行任何跨节点协调。全局驱动程序(例如“叠加层”)依赖 图书馆 (键值存储抽象)以跨机器进行协调。此键值存储是另一个插件接口,并且是非常低级的(键和值,没有语义)。为了在Kubernetes集群中运行类似Docker的覆盖驱动程序之类的东西,我们要么需要集群管理员来运行一个完全不同的实例, 领事, 要么 动物园管理员 (看到 多主机联网),否则我们将不得不提供由Kubernetes支持的我们自己的libkv实现。

后者听起来很吸引人,我们尝试实现它,但是libkv接口非常底层,并且该模式在Docker内部定义。我们将不得不直接公开我们的基础键值存储,或者提供键值语义(在我们本身是在键值系统上实现的结构化API之上)。出于性能,可伸缩性和安全性原因,这两种方法都不具有吸引力。最终结果是,当使用Docker网络的目的是简化事情时,整个系统将变得更加复杂。

对于愿意并能够运行必要基础架构来满足Docker全局驱动程序并自己配置Docker的用户,Docker网络应该“正常工作”。 Kubernetes不会妨碍这种设置,并且无论项目的发展方向如何,该选项都应该可用。但是,对于默认安装,实际的结论是,这给用户带来了不必要的负担,因此我们不能使用Docker的全局驱动程序(包括“ overlay”),这完全消除了使用Docker插件的很多价值。

Docker's networking model makes a lot of assumptions that aren’t valid for Kubernetes. In docker versions 1.8 and 1.9, it includes a fundamentally flawed implementation of "discovery" that results in corrupted /etc/hosts files in containers (码头工人#17190),并且无法轻易将其关闭。在1.10版中,Docker计划 捆绑新的DNS服务器,目前尚不清楚是否可以将其关闭。容器级命名不是Kubernetes的正确抽象-我们已经拥有了自己的服务命名,发现和绑定概念,并且我们已经拥有了自己的DNS模式和服务器(基于公认的 天空DNS)。捆绑的解决方案不足以满足我们的需求,但不能禁用。

正交于本地/全局拆分,Docker同时具有进程内和进程外(“远程”)插件。我们研究了是否可以绕过libnetwork(从而跳过上面的问题)并直接驱动Docker远程插件。不幸的是,这意味着我们不能使用任何Docker进程内插件,尤其是“ bridge”和“ overlay”,这再次消除了libnetwork的许多实用程序。

另一方面,CNI在哲学上与Kubernetes保持一致。它比CNM简单得多,不需要守护程序,并且至少可以说是跨平台的(CoreOS的 t 容器运行时支持它)。跨平台意味着有机会启用在运行时相同的网络配置(例如Docker,Rocket,Hyper)。它遵循UNIX哲学,把一件事做好。

此外,包装CNI插件并生成更自定义的CNI插件很简单-只需使用简单的shell脚本即可完成。 CNM在这方面要复杂得多。这使CNI成为快速开发和迭代的有吸引力的选择。早期的原型已经证明,可以将kubelet中当前硬编码的网络逻辑中几乎100%弹出到插件中。

我们调查了 编写“网桥” CNM驱动程序 适用于运行CNI驱动程序的Docker。事实证明这很复杂。首先,CNM和CNI模型有很大的不同,因此没有“方法”。上面讨论的仍然是全球性,本地性和键值问题。假设该驱动程序将自己声明为本地驱动程序,我们必须从Kubernetes获取有关逻辑网络的信息。

不幸的是,Docker驱动程序很难映射到Kubernetes等其他控制平面。具体来说,不会告诉驱动程序容器所连接到的网络的名称,而只是告诉Docker内部分配的ID。这使得驱动程序很难映射回另一个系统中存在的任何网络概念。

网络供应商已将这个问题和其他问题提交给Docker开发人员,通常以“按预期工作”的方式关闭(lib网络#139, lib网络#486, lib网络#514, lib网络#865, 码头工人#18864),即使它们使非Docker第三方系统更难以集成。在整个调查过程中,Docker明确表示,他们对偏离当前课程或委托控制的想法不是很开放。这对我们来说非常令人担忧,因为Kubernetes是对Docker的补充,并增加了很多功能,但它存在于Docker本身之外。

For all of these reasons we have chosen to invest in CNI as the Kubernetes plugin model. There will be some unfortunate side-effects of this. Most of them are relatively minor (for example, docker inspect will not show an IP address), but some are significant. In particular, containers started by docker run might not be able to communicate with containers started by Kubernetes, and network integrators will have to provide CNI drivers if they want to fully integrate with Kubernetes. On the other hand, Kubernetes will get simpler and more flexible, and a lot of the ugliness of early bootstrapping (such as configuring Docker to use our bridge) will go away.

当我们沿着这条道路前进时,我们一定会睁大眼睛,以寻求更好的集成和简化方法。如果您对我们该如何做有想法,我们真的很想听听他们的意见-找到我们 松弛 或在我们的 网络SIG邮件列表.

Google软件工程师Tim Hockin