文档结构  
翻译进度:已翻译     翻译赏金:0 元 (?)    ¥ 我要打赏

自从之前1.0版本发布之后,Kubernetes一直有一个非常基础形式的网络插件— 而1.0版本的发布时间,大概与Docker的libnetwork和容器网络模型(Container Network Model,CNM)发布时间近似。不像libnetwork,Kubernetes的插件系统仍然保持着它的“阿尔法”版本。既然Docker的网络插件支持已经发布并应用了,一个明显的的问题是为什么Kubernetes还没有采用它。毕竟,厂商们基本肯定会为Docker写插件的——使用同样的驱动对我们来说更好,对吗?

在深入讨论之前,提醒大家一个重点:Kubernetes是一个系统,支持多种容器运行时环境,Docker只是其中之一。配置网络是每个运行时环境的一个方面,因此有人问“Kubernetes会支持CNM吗?”他们真正的意思是:“Kubernetes会使用Docker运行时环境支持CNM驱动吗?”如果我们能够在不同运行时环境中应用共同的网络支持,那会很棒,但这不是一个明确的目标。

第 1 段(可获 2.04 积分)

事实上,Kubernetes还没有为Docker运行时环境采用CNM/libnetwork。实际上,我们调研了CoreOS和部分App容器(appc)规范提出的提到替代性容器网络结构(CNI)。为什么呢?这其中有一些技术和非技术的原因。

首先,最重要的是,Docker的网络驱动设计用到了一些基础假设,这些假设为我们带来了麻烦。

Docker有一个“本地”和“全局”驱动的概念。本地驱动(例如“网桥”)以机器为中心,不进行任何跨节点调度。全局驱动(例如“overlay,覆盖网络”)依靠 libkv(一种key-value存储抽象)来跨机器协同。这个key-value存储是另一个插件接口,而且抽象非常底层(只有key和value,没有任何语义)。为了在Kubernetes集群中运行类似Docker的overlay驱动,我们要么需要集群管理员运行consuletcdzookeeper(参考 multi-host networking)的完全另一个实例,或者我们要提供由Kubernetes支持的自己的libkv的实现。

第 2 段(可获 2.16 积分)

后者听起来很有吸引力,我们试图实现它,但libkv的接口非常底层,而且其模式是定义在Docker内部的。我们得要么直接暴露我们底层的key-value存储,或者提供key-value语义(在我们基于key-value系统实现的结构化API之上)。出于性能、可扩展性和安全原因,这两者都不是很有吸引力。最终结果是整个系统大幅复杂化了,但使用Docker网络的目标本是简化操作。

第 3 段(可获 1.14 积分)

 

对于那些愿意并能够运行必要的基础设施来满足Docker的目标驱动,并配置Docker自身的用户来说,Docker网络不应当“只是能工作。”Kubernetes不会插手这项设置,而且不论工程走向如何,Kubernetes应当是能支持网络配置的。然而对于默认安装,实践结论是这对用户有过度的负担,因此我们无法使用Docker的全局驱动(包括overlay),这导致使用Docker插件的价值被削弱了很多。

第 4 段(可获 1.15 积分)

Docker的网络模型进行了很多假设,这些假设对于Kubernetes都是不适用的。在Docker 1.8和1.9版本中,它包含了一个有缺陷的“容器发现”的实现,这导致容器中的/etc/hosts 文件冲突(docker #17190)——而且这个问题很难修复。在1.10版本中,Docker计划提供一个新的DNS服务器,而且不清楚为什么这样会修复问题。容器级别的命名对于Kubernetes来说不是正确的抽象——我们已经有自己的服务命名、发现和绑定的概念了,而且我们已经有自己的DNS模式和服务器了(基于完善的SkyDNS)。Docker提供的解决方案无法满足我们的需求,又无法关掉。

第 5 段(可获 1.53 积分)

与本地/全局的区分正交的是,Docker同时拥有进程内和进程外(“远程”)的插件。我们调查了我们是否可以绕过libnetwork(从而跳过上述问题)并直接驱动Docker的远程插件。不幸的是,这意味着我们不能使用任何Docker进程内插件,尤其是“网桥”和“overlay”,这又一次削弱了libnetwork的用处。

另一方面,CNI与Kubernetes的理念更相符。它比CNM要简单很多,不需要守护进程,而且至少在多个平台上可用(CoreOS的rkt容器运行时环境支持它)。能够跨平台意味着有可能在不同运行时环境中使用同样工作方式的网络配置(如Docker,Rocket,Hyper)。这遵循了UNIX的哲学:把一件事情做好(Doing one thing well)。

第 6 段(可获 1.63 积分)

另外,打包一个CNI插件并制作一个定制化的CNI插件非常容易——通过一个简单的命令行脚本就能做到。CNM在这方面就要复杂得多。这使得CNI成为快速开发和迭代的绝佳选择。早期原型系统证明了我们可以将几乎100%的在kubelet中硬编码的网络逻辑移到一个插件里面。

我们调研了用于Docker的,运行CNI驱动器的写一个“网桥”CNM驱动器。这非常复杂。首先,CNM和CNI模型非常不同,因此两种“方法”没有良好匹配。我们同样遇到了上面讨论的本地vs.全局和key-value的问题。假设这个驱动器声明自己是本地的,我们不得不从Kubernetes里面获取关于逻辑网络的信息。

第 7 段(可获 1.65 积分)

 

不幸的是,Docker驱动器很难与包括Kubernetes在内的其他控制平面匹配。特别地,驱动无法知道容器附着的网络的名称——只有一个Docker内部分配的ID。这导致一个驱动很难将网络匹配到其它系统中的网络概念里面。

这与一些其他的问题(issue)由网络厂商提出,送到了Docker开发者面前(libnetwork #139 , libnetwork #486 , libnetwork #514 , libnetwork #865, docker #18864),但经常会以“正如我们预期地工作”为由被关闭了,即使这导致更难与Docker之外的第三方系统集成。通过这次调查,Docker已经明确地表现出他们是很接受与他们目前的实现和委托控制不同的想法。这对我们来说很值得担忧,因为Kubernetes完善了Docker,而且增加了很多功能,但仍无法融入Docker。

第 8 段(可获 1.85 积分)

因为上述所有原因,我们选择了在CNI方面投入,用于开发Kubernetes的插件模型。这会有一些不幸的负面效果。它们大多数相对不重要(例如:

docker inspect

不会显示IP地址),但有一些是很重要的。特别地,用

docker run

命令启动的容器可能无法与Kubernetes启动的容器通信,而且网络集成商如果想要完全集成Kubernetes的话,不得不提供CNI驱动。另一方面,Kubernetes能变得更加简单和灵活,而且一些早期丑陋的实现(例如配置Docker使用我们的网桥)会不再被采用。

第 9 段(可获 1.34 积分)

随着我们在这条道路上继续前行,我们当然会随时乐意接受易于集成而且简单的新方法。如果你有任何想法,我们很愿意听到他们——通过slack或我们的网络特殊兴趣小组邮件组联系我们。

Tim Hockin,Google软件工程师

第 10 段(可获 0.68 积分)

文章评论