为什么Kubernetes不使用libnetwork
Kubernetes 在 1.0 版本之前就已经有了最初的网络插件。与此同时 Docker 也引入了 libnetwork 和 Container Network Model (CNM)。现在 Docker 已经发布并支持了网络插件 libnetwork,然而 Kubernetes 的插件却还停留在 alpha 阶段。 那么一个显而易见的问题是为什么 Kubernetes 还没有采用 libnetwork。毕竟大部分的供应商都肯定会支持 Docker 的插件,Kubernetes 也理所应当采用它。
在开始讨论之前,我们首先需要知道的一点是: Kubernetes 是一个支持多种容器运行环境的系统,Docker 只是其中之一。配置网络对于每个运行环境都是同样重要的。所以当人们问到“ Kubernetes 支持不支持 CNM 时”,他们其实是在问“Kubernetes 会不会在 Docker 运行环境下支持 CNM”。我们当然希望利用同样一个网络插件来支持所有的运行环境,但是这并不是一个绝对的目标。
然而,Kubernetes 并没有在其 Docker 运行环境中采用 CNM/libnetwork。最近一段时间,我们一直在研究探讨能否使用 CoreOS 推出的 App Container (appc) 中的网络模型Container Network Interface (CNI) 去替代它。为什么?这里面有各种技术上和非技术上的原因。
首先,Docker 的网络驱动设计做了一些兼容性不佳的基本假设,这给我们带来了不少困难。
比如 Docker 里面有本地和全局驱动的概念。本地驱动(比如 “bridge”)固定于一台机器而不能做跨机器的远程协调。全局驱动(比如 “overlay”)依赖于 libkv 库去做跨机器间的协调。该库定义了一个 key-value 存储的接口,并且接口非常的底层。为了让 Docker 的全局驱动在 Kubernetes 集群上跑起来,我们还得需要系统管理员去运行 etcd, ZooKeeper, Consul 的实例(具体看 Docker 的 multi-host network 文档); 或者我们得在 Kubernetes 里面提供另一套 libkv 的实现。
不过相比之下,第二种方案(全局驱动)看起来更灵活,更好,所以我们尝试去实现它。但是 libkv 的接口非常底层,它的模式也是为了 Docker 运行环境自身设计的。对于 Kubernetes 来说,我们要么直接暴露出我们的底层 key-value 接口,要么提供一个 key-value 的语义接口(也就是在一个key-value系统上实现结构存储的API)。就性能、伸缩性和安全角度而言,这两个选择对我们来说并不是非常合适。如果我们这样实现的话,整个系统会变明显地变得复杂。这和我们希望利用Docker的网络模型来简化实现所冲突。
对于想要运行 Docker 的全局驱动并能有能力配置 Docker 的用户来说,Docker 的网络应该会运行得很好。对 Kubernetes 来说,我们不希望介入或影响 Docker 的配置步骤;并且不论 Kubernetes 这个项目今后如何发展,这一点应该不会改变。甚至,我们会努力兼容更多的选项给用户。但我们在实践过程中得到的结论是:Docker 的全局驱动是对用户和开发者来说增加了多余的负担,并且我们不会用它作为默认的网络选项——这也意味着使用 Docker 插件的价值很大程度上被排除在外。
与此同时,Docker 的网络模型在设计上还做了很多和 Kubernetes 不兼容的假设。比如说在 Docker 1.8 和 1.9 的版本中,它在实现“服务发现(Service discovery)”时有一个根本性的设计缺陷,结果导致了容器中的 /etc/hosts 文件被随意改写甚至破坏(docker #17190 ) ——而且我们还不能轻易关闭“服务发现”这个功能。在 1.10 的版本中,Docker 还计划增加捆绑一个新 DNS 服务器 的功能,而我们现在还不不清楚这个功能能否被关闭。对 Kubernetes 来说,把命名寻址绑定在容器层面,并不是一个正确的设计——我们已经自己定义了一套 Service 命名、寻址、绑定的概念和规则,并且我们也有了我们自己的 DNS 架构和服务(构建在非常成熟的 SkyDNS 上)。所以,捆绑一个 DNS 服务器这样的方案并不能满足我们的需求,而且它还有可能无法被关闭。
除开所谓“本地”,“全局”驱动这样的区分,Docker 还定义了“进程内”和“进程外”(“远程”)插件。我们还研究了下是否可以绕过 libnework 本身(这样就能避开之前所述的那些问题)来直接使用”远程“插件。不幸的是,这意味着我们同时也失去了使用 Docker 的那些“进程内”插件的可能,特别是像网桥(bridge)和覆盖网络(overlay)这样的插件。这令使用 libnetwork 这件事本身失去了很大一部分意义。
另一方面,CNI 和 Kubernetes 在设计哲学上就非常一致。它远比 CNM 简单,不需要守护进程,并且至少是跨平台的(CoreOS 的 rkt 容器支持 CNI)。跨平台意味着同一个网络配置可以在多个运行环境下使用(例如 Docker, rkt 和 Hyper)。这也非常符合 Unix 的设计哲学:把一件事情做好。
另外,包装 CNI 模块来实现一个更定制的模块是非常简单的-写一个简单的 shell 脚本就可以完成。相反 CNM 就复杂多了。因此我们认为 CNI 更适合快速开发和迭代。早期的实验尝试证明我们可以利用 CNI 插件来替代几乎所有 kubelet 中硬编码的网络逻辑。
我们也尝试为 Docker 实现了一个网桥(bridge)CNM 驱动来使用 CNI 的驱动。结果表明这更加复杂了问题。首先 CNM 和 CNI 的模型非常不同,没有一个“方法”能把它们很好的兼容起来。其次,我们还是有之前提到的“全局”和“本地”以及 key-value 的问题存在。假设这是个本地驱动,那么我们仍旧要从 Kubernetes 中去得到相应的逻辑网络的信息。
不幸的是,对于像 Kubernetes 这样的管理平台而言,Docker 的驱动非常难以接入。特别是这些驱动使用了 Docker 内部分配的一个 ID 而不是一个通用的网络名字来指向一个容器所属的网络。这样的设计导致一个被定义在外部系统中(例如 Kubernetes )的网络很难被驱动所理解识别。
我们和其它网络提供商将这些问题和其它一些相关问题都汇报给了 Docker 的开发人员。尽管这些问题给非 Docker 的第三方系统带来了很多困扰,它们通常被以“设计就是如此”的理由所关闭(libnetwork #139, libnetwork #486, libnetwork #514, libnetwork #865, docker #18864)。通过这些举动,我们观察到 Docker 清楚的表明了他们对于有些建议的态度不够开放,因为这些建议可能会分散其一些主要精力、或者降低其对项目的控制。这一点让我们很着急,因为 Kubernetes 一直支持 Docker,并且为其增加了如此多的功能,但同时 Kubernetes 也是一个独立于 Docker 之外的项目。
种种原因致使我们选择了 CNI 作为 Kubernetes 的网络模型。这将会带来一些令人遗憾的副作用,虽然绝大部分都是一些小问题,比如 Docker 的 inspect 命令显示不了网络地址。不过也会有一些显著的问题,特别是被 Docker 所启动的容器可能不能和被 Kubernetes 启动的容器沟通,以及网络整合工程师必须提供 CNI 驱动来把网络完全整合到 Kubernetes 中。但重要的是,Kubernetes 会变得更简单、灵活并且不需要进行提前配置(比如配置 Docker 使用我们的网桥)。
随着我们越走越远,我们会毋庸置疑地汲取更多更好的整合、简化的方法。如果您对此有啥想法,我们洗耳恭听——可以通过 Slack (http://slack.k8s.io/) 和 network SIG 邮件列表联系我们。
原文链接:Why Kubernetes doesn’t use libnetwork
为什么Kubernetes不使用libnetwork的更多相关文章
- 浅析Kubernetes的工作原理
先放一张Kubernetes的架构图: 整体来看,是一个老大,多个干活的这种结构,基本上所有的分布式系统都是这样,但是里面的组件名称就纷繁复杂,下面将一一解析. 1.元数据存储与集群维护 作为一个集群 ...
- Kubernetes网络的4种解决方案
一.Kubernetes + Flannel Kubernetes的网络模型假定了所有Pod都在一个可以直接连通的扁平的网络空间中,这在GCE(Google Compute Engine)里面是现成的 ...
- 基于Kubernetes(k8s)网络方案演进
VIP PaaS在接近两年时间里,基于kubernetes主要经历四次网络方案的变迁: 1. kubernetes + flannel 2. 基于Docker libnetwork的网络定制 3. k ...
- kubernetes,Docker网络相关资料链接
1.Why kubernetes not doesn't use libnetwork http://blog.kubernetes.io/2016/01/why-Kubernetes-doesnt- ...
- kubernetes大概的工作原理
先放一张Kubernetes的架构图: 整体来看,是一个老大,多个干活的这种结构,基本上所有的分布式系统都是这样,但是里面的组件名称就纷繁复杂,下面将一一解析. 1.元数据存储与集群维护 作为一个集群 ...
- 深入解读docker网络与kubernetes网络
前言:你是否学习使用k8s很久很久了可是对于网络这块仍旧似懂非懂呢? 您是否对网上一堆帖子有如下的抱怨: 打开多个博客,然后发现有区别么? 明显是直译过来的,越看越迷糊 “因为xxx,所以yyy”,. ...
- Kubernetes CNI网络插件
CNI 容器网络接口,就是在网络解决方案由网络插件提供,这些插件配置容器网络则通过CNI定义的接口来完成,也就是CNI定义的是容器运行环境与网络插件之间的接口规范.这个接口只关心容器的网络连接,在创建 ...
- Docker Swarm和Kubernetes在大规模集群中的性能比较
Contents 这篇文章主要针对Docker Swarm和Kubernetes在大规模部署的条件下的3个问题展开讨论.在大规模部署下,它们的性能如何?它们是否可以被批量操作?需要采取何种措施来支持他 ...
- [笔记]kubernetes 无法启动问题
在启动kubernetes的时候报错误. ERROR: timed out for http://localhost:4001/v2/keys/ 原因是无法启动etcd, etcd 监听4001本地端 ...
随机推荐
- json/pickle/shelve/xml/configparser/hashlib/subprocess - 总结
序列化:序列化指把内存里的数据类型转成字符串,以使其能存储到硬盘或通过网络传输到远程,因为硬盘或网络传输时只能接受bytes为什么要序列化:可以直接把内存数据(eg:10个列表,3个嵌套字典)存到硬盘 ...
- 剑指Offer——用两个栈实现队列
题目描述: 用两个栈来实现一个队列,完成队列的Push和Pop操作. 队列中的元素为int类型. 分析: 代码: class Solution { public: void push(int node ...
- "零代码”开发B/S企业管理软件之一 :怎么创建数据库表
声明:该软件为本人原创作品,多年来一直在使用该软件做项目,软件本身也一直在改善,在增加新的功能.但一个人总是会有很多考虑不周全的地方,希望能找到做同类软件的同行一起探讨. 本人文笔不行,能把意思表达清 ...
- 微信js分享朋友圈(一)
1.绑定域名 先登录微信公众平台进入“公众号设置”的“功能设置”里填写“JS接口安全域名”. 备注:登录后可在“开发者中心”查看对应的接口权限. 2.引入js文件 <script type=&q ...
- 【转】HTTP缓存机制
前言 Http 缓存机制作为 web 性能优化的重要手段,对于从事 Web 开发的同学们来说,应该是知识体系库中的一个基础环节,同时对于有志成为前端架构师的同学来说是必备的知识技能.但是对于很多前端同 ...
- 携程greenlet模块使用
import greenlet def f1(): print(11) gr2.switch() print(22) gr2.switch() def f2(): print(33) gr1.swit ...
- Django继承
Django目前支持两种不同的继承方式,包括抽象基础类和多表继承. 1.抽象基础类: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 cla ...
- JAVA三框架工作原理是什么?
一.struts的工作原理: 1.初始化,读取struts-config.xml.web.xml等配置文件(所有配置文件的初始化) 2.发送HTTP请求,客户端发送以.do结尾的请求 3.填充Form ...
- vue中的锚点和查询字符串
1.什么是锚点 锚点(achor):其实就是超链接的一种. 如:普通的超链接 <a href="sub_task_detail.php">详细</a> 主 ...
- kmp模板 && 扩展kmp模板
kmp模板: #include <bits/stdc++.h> #define PB push_back #define MP make_pair using namespace std; ...