上周,在 Kubecon 欧洲在线虚拟大会上,Kubernetes 的两位早期开发者 Brendan Burns 和 Tim Hockin 针对大家的提问“谷歌会不会从 Borg 迁移到 Kubernetes”进行了回复。
作为谷歌开源的容器集群管理系统,Kubernetes 建立在谷歌内部的 Borg 技术之上。发展到今天,Kubernetes 的规模已经变得非常庞大,它被认为是计算基础设施的未来,与虚拟机一脉相承,就像虚拟机取代裸机成为计算部署的最常见单元一样,尤其是在云环境中。
作为业界最主流的容器技术,谷歌会不会考虑迁移到 Kubernetes 呢?
Hockin 表示,“Kubernetes 和 Borg 在思想上非常相似,但在细节上有很大的不同。Borg 没有像 Kubernetes 那样的网络模型。Borg 应用程序是为了在 Borg 中运行而编写的,因此它可以更具规范性,Borg 应用程序是高度同质化的:同样的库、同样的 RPC 系统、同样的认证。”
“最关键的是 Kubernetes 的设计是为了与现有的开源系统一起工作。虽然它们都专注于自动化、短暂性、动态管理,以及让用户在大多数情况下不必关心与他们无关紧要的细节。” “我们已经在 Kubernetes 上运行了一些云服务,但 Borg 有超过 14 年以上的定制功能,如搜索、广告、Gmail 等,而 Kubernetes 并不需要这些定制功能。”
“我们将 Kubernetes 作为一个整体来介绍,因为它一下子解决了一类问题,但每一个部分真的是不同的,” Hockin 说,“Kubernetes 的 API 部分非常‘薄’——几乎所有的执行都是与 API 异步的,而且完全可以替换。”
是 Kubernetes 太复杂了吗?“肯定的,Kubernetes 很复杂,因为它有 100 多个不同的 API 协同工作,有很多可动部件和子系统。但我并不认为它比任何其他类似操作系统的东西更复杂。我对简单性和复杂性的想法很纠结。我们能让它变得更简单吗?当然能,可代价是什么?你愿意删减那些功能吗?事实是,每个功能都有人在用。”
至于未来的关注点,Hockin 说,“我会更多地专注于模块解耦。我会更努力地主张嵌套命名空间。我会让集群边缘的墙变得不那么坚不可摧。我会把更多的精力放在 API 机制上,作为一种 IDL(Interface Definition Language,接口描述语言)——API 核心的更强大的功能。”
联合创始人 Brendan Burns 也在第二天上场接受了盘问。和 Hockin 一样,他也对 Kubernetes 的发展进行了反思。他被问及一开始有没有想过 Kubernetes 会变得这么大?他回答道:“我们看到了相关领域的空白,相信会有东西出现并填补它,但我无法保证那一定会是 Kubernetes。当时,有相当多的可选方案。”
Kubernetes 和 Borg 的区别
Kubernetes “始于 2013 年秋天”,彼时 Burns、Joe Bida 和 Craig McLuckie 受到 Docker 工具和容器标准化潜力的启发,开始着手创建一个 “最小可行的编排器”。谷歌对容器并不陌生,因为它已经运行了一个 “统一容器管理系统……内部称之为 Borg。”
尽管 Kubernetes 在某些方面是 Borg 的进化,但一个关键的区别是,Kubernetes 一直是为外部开发者准备的。Burns 介绍称,他们还 “花了很多很多的时间” 来 “说服执行领导层,让他们相信开源这个项目是个好主意”。
2015 年,谷歌发布了 Kubernetes v1.0,同时联合 Redhat 以及 Microsoft 等公司成立了云原生计算基金会(Cloud Native Computing Foundation,CNCF),并将 Kubernetes 作为种子项目捐赠给了 CNCF。
虽然 Kubernetes 来源于 Borg,但两者也有一些区别,Brian Grant 还曾特地对此做了阐述。
Borg 作为谷歌的内部容器管理平台,继承了之前谷歌 WorkQueue(用于批处理作业)和 Babysitter(用于在服务器上管理的连续运行服务)所使用的应用管理项目。当时处于多核时代的早期阶段,谷歌以使用廉价的现成硬件而闻名。所以,谷歌的机器并不是那种拥有无数处理器的巨大盒子,早期的系统相当简单。
WorkQueue 仅仅是基于内存为机器调度工作负载,而机器的所有其他方面都是差不多的。一旦多核错误出现,人们开始意识到,需要一些更强大的东西来进行 Binpack,这就是 Borg 的真正动机。实际上,它被设计成直接滑入工作队列中,并用于调度 Map Reduce,它现在甚至运行在 WorkQueue 运行的同一端口上。它还覆盖了一些 Babysitter 的角色,所以它实际上创建了一个统一的平台,人们可以在这个平台上同时运行服务和批处理负载,以及其他工作负载,所有类型的工作负载——最终,谷歌现在几乎所有的东西都在 Borg 上运行。
当 Brian Grant 刚加入谷歌的时候,恰逢一个巨大的转变:“Everything On Borg”,目的就是要是让所有的工作负载都转移到 Borg 上。
从那开始,谷歌前前后后发展出了三个容器系统:Borg、Omega 以及 Kubernetes。事实上,Omega 是 Grant 在 2009 年初加入 Borg 团队后不久创立的产品,他已经在这个领域工作了 10 年,在此之前一直研究高性能计算。
Grant 说:“我观察人们是如何利用 Borg 的,以及它在可扩展性和可伸缩性方面存在的问题,并对一些用例做了更好的处理。这也是 Omega 项目的动机,它实际上是一个试图找出如何改进 Borg 中的一些底层原语和内部基础设施的项目。
这是一个全新的项目,从零开始,Omega 有许多属性同样可以在 Kubernetes 中看到。事实上,Kubernetes 更像是一个开源的 Omega,而不是开源的 Borg。很多参与 Omega 工作的人也参与了 Kubernetes 的开发工作,因此 Omega 的很多想法也进入了 Kubernetes。”
“有的还被反馈回了 Borg。它确实在生产环境中运行了一段时间,但随着时间的推移,它又统一回到了 Borg 中,因此,像多调度器这样的想法实际上甚至早于 Omega 在这方面的一些工作。” Grant 补充说。
Omega 当时要解决的是 Borg 的一个大问题,Borg Master,尤其是 Borg 的控制面板,并没有设计成具有可扩展性的概念空间。它有一个非常有限的、固定数量的概念,包括机器、作业等概念。Alex 是可以将作业调度到其中的一系列资源,以及称为 Packages(包)的原语,它们实际上只是关于将要安装的软件包的命令和元数据,Packages 是 Borg 的。就像容器映像的一部分。除了像卷这样的东西之外,容器映像在某种程度上是单体(monolithic)的。Borg 内部的包机制被设计成更具组合性。
据 Grant 称,人们可以在谷歌上搜索 2006 年的那篇论文看看,它是一个 Key-Value Store,激发了 ZooKeeper 和 consul、etcd。因此,Borgmaster 将其状态存储在一个由各个 Borgmaster 二进制文件编写的检查点中。它没有单独的存储组件,这使得某些事情(比如灾难恢复)变得更具挑战性。
它可以与控制面板实例本身分开管理。所以,这就是最终的改变之一,基于 Praxis 的 Store 实现被并回 Borgmaster,这得益于重用了 Chubby 非常可靠的生产代码。这实际上也使得它可以停止使用 Chubby 来做某些事情,比如集群领导选举,因为它可以使用自己的 Store 来实现这个目的。
另外,Borg 为应用程序动态分配端口,而不是像 Kubernetes 那样分配 IP。这样做的好处是不需要那么多 IP 地址,至于缺点,其中一个就是,在谷歌内部,大多数软件都是从头开始重写的。因此,谷歌的 monorepo 中有数十亿行代码,都是从头开始编写的。如果你能做到这一点,那么就可以与外界的做法大相径庭。如果真的需要能够从外部世界管理,就会变得更难。因此,外部世界中的大多数应用程序都采用静态配置的端口。如果你有一个分布式应用程序,它们通常会假定该应用程序的所有实例都在同一端口上。
例如,它们可能只共享 IP 地址或 DNS 名称,甚至并不会共享它们所在的端口。一般说来,人们使用 DNS 的方式,只是用来查找 IPv4 或 IPv6 地址,而不是查看端口。因为它们都假定客户端都知道端口,鉴于它们使用了已知的端口这一事实。
大多数代理只处理所有位于同一端口上的目标。因此,在几乎所有以任何一种分布式方式运行在服务器上的软件中,这是一个普遍存在的问题。因此谷歌决定尝试给这些应用程序的配置和发现以及负载均衡,提供更为实用的模型。这也是造成差异的真正原因。总结来说,Kubernetes 之所以能发展成现在这个样子,也是因为早期开发者都来自于 Borg,懂得其中的差异。
Kubernetes 的复杂性
从诞生之日起,复杂性就一直伴随着 Kubernetes 项目。针对此问题,InfoQ 曾进行过相关报道和采访。阿里巴巴高级技术专家张磊在采访中表示,Kubernetes 对于大多数开发人员来说,确实是一个比较复杂的开源项目。
这一“复杂性”部分源自 Kubernetes 本身的设计思想和定位。Kubernetes 本质上是一个分布式系统而不是一个简单的 SDK 或者编程框架,这本身已经将其复杂度提升到了系统级分布式开源项目的位置(换言之,不可以简单地将 Kubernetes 的复杂性与编程框架等同日而语)。此外,Kubernetes 第一次将声明式 API 的思想在开源基础设施领域普及开来,并以此为基础提出了系列诸如容器设计模式和控制器模型等使用范式,这些具有一定先进性和前瞻性的设计也使得 Kubernetes 项目被大众接受需要一定的学习周期。
但开源项目是否被认为“复杂”,更大程度取决于使用者对该项目的具体诉求。Kubernetes 时不时被控诉“复杂”,更主要还是源自不同用户群体诉求与 Kubernetes 项目自身定位的“错位关系”。
Kubernetes 项目的核心定位是要做一个“Platform for Platform”的项目,即“用来帮助使用者构建分布式系统的分布式系统”。这也意味着,Kubernetes 项目的首要目标用户其实是分布式应用的开发人员。这里的分布式应用可以是稍具规模的网站,也可以是 TiDB 这样复杂的数据库系统。但这也就使得对不少技术从业者来说,Kubernetes 项目的很多设计与思想,都会比较难以一下子被理解和接受。
除了分布式应用的开发者,在 Kubernetes 项目当前的使用者群体中,还有很大一部分来自于 Docker 生态以及 PaaS 社区,这些用户往往是普通应用而非复杂应用的开发者。相比于纠结“高可用”、“高性能”和“大规模”,这些用户关注的价值点是他们编写的业务逻辑本身,而非程序和代码。对于这些用户来说,他们希望 Kubernetes 提供的,其实是朴素的应用托管和底层基础设施屏蔽能力。这些诉求对于 Kubernetes 项目来说当然不是问题,但是却很难透出 Kubernetes 项目核心设计思想带来的种种好处。
此外,Kubernetes 项目还有一部分用户是应用运维人员。对于这些用户来说,他们希望 Kubernetes 提供的主要是基础设施与资源管理能力,以帮助他们来运维业务方即应用开发者编写的应用。在这个场景下,Kubernetes 项目本身自然也没有问题。但是传统运维模式与 Kubernetes 提倡的声明式 API 和控制器模型之间,其实有着不小的思想与技术鸿沟需要跨越。
不过从 Kubernetes 过去的发展来看,复杂性问题并没有对 Kubernetes 本身带来太大影响。Kubernetes 项目的核心理念以及“Platform for Platform“的定位催生出整个云原生的生态,才是其社区迅猛增长的主要动力源泉。当然,Kubernetes 社区也持续在民主化和可扩展方向上不断演进,并尝试通过实现开发与运维等使用者角色的解耦来解决上述“复杂性”问题。
此外,CNCF 执行官 Chris Aniszczyk 强调:虽然分布式系统本质上很复杂,但 Kubernetes 的优势在于全球每个主流云厂商都提供符合认证的版本(无分支),这对大多数用户来说可以缓解大规模管理的复杂性。