十多年来从三个容器管理系统中吸取的教训
十多年来从三个容器管理系统中吸取的教训
Brendan Burns、Brian Grant、David Oppenheimer、Eric Brewer 和 John Wilkes,谷歌公司。
尽管对软件容器的广泛兴趣是一个相对较新的现象,但在 Google,我们已经大规模管理 Linux 容器十多年了,并且在那段时间构建了三种不同的容器管理系统。每个系统都受到其前身的严重影响,即使它们是出于不同的原因而开发的。本文描述了我们从开发和操作它们中学到的经验教训。
Google 开发的第一个统一容器管理系统是我们内部称为 Borg 的系统。7它旨在管理长期运行的服务和批处理作业,这些作业以前由两个独立的系统处理:Babysitter 和 Global Work Queue。后者的架构强烈影响了 Borg,但专注于批处理作业;两个都早于 Linux 控制组。Borg 在这两种类型的应用程序之间共享机器,以此作为提高资源利用率从而降低成本的一种方式。这种共享是可能的,因为 Linux 内核中的容器支持变得可用(实际上,谷歌将大部分容器代码贡献给了 Linux 内核),这使得延迟敏感的面向用户的服务和 CPU 饥渴的批处理之间实现了更好的隔离。
随着越来越多的应用程序被开发出来运行在 Borg 之上,我们的应用程序和基础设施团队为其开发了一个广泛的工具和服务生态系统。这些系统提供了配置和更新作业的机制;预测资源需求;动态推送配置文件到正在运行的作业;服务发现和负载均衡;自动缩放;机器生命周期管理;配额管理;还有更多。这个生态系统的发展是由 Google 内部不同团队的需求驱动的,结果是 Borg 的用户必须使用几种不同的配置语言和流程来配置和交互的有点异构的、临时的系统集合。Borg 仍然是 Google 内部的主要容器管理系统,因为它的规模、功能的广度、
Omega是 Borg 的后代,6岁,其驱动力是希望改进 Borg 生态系统的软件工程。它应用了许多在 Borg 中被证明是成功的模式,但它是从头开始构建的,以拥有更一致、更有原则的架构。Omega 将集群的状态存储在一个集中的基于 Paxos 的面向事务的存储中,该存储由集群控制平面的不同部分(例如调度程序)访问,使用乐观并发控制来处理偶尔的冲突。这种解耦允许 Borgmaster 的功能被分解为充当对等体的单独组件,而不是通过一个单一的、集中的 master 汇集每个更改。Omega 的许多创新(包括多个调度器)已被合并到 Borg 中。
Google 开发的第三个容器管理系统是 Kubernetes。4它是在外部开发人员对 Linux 容器产生兴趣的世界中构思和开发的,谷歌开发了一项不断增长的业务,销售公共云基础设施。Kubernetes 是开源的——与 Borg 和 Omega 形成对比,后者是作为纯粹的 Google 内部系统开发的。与 Omega 一样,Kubernetes 的核心是一个共享的持久存储,组件监视相关对象的更改。与将存储直接暴露给受信任的控制平面组件的 Omega 相比,Kubernetes 中的状态仅通过域特定的 REST API 访问,该 API 应用更高级别的版本控制、验证、语义和策略,以支持更多样化的客户群。更重要的是,
本文介绍了在 Google 从 Borg 到 Kubernetes 的过程中获得的一些知识和教训。
容器
从历史上看,第一个容器只是提供了根文件系统的隔离(通过 chroot),FreeBSD jail 将其扩展到额外的命名空间,例如进程 ID。Solaris 随后开创并探索了许多增强功能。Linux 控制组 (cgroups) 采用了许多这样的想法,并且这一领域的发展一直持续到今天。
容器提供的资源隔离使谷歌的利用率大大高于行业规范。例如,Borg 使用容器将批处理作业与延迟敏感、面向用户的作业放在同一台物理机器上。面向用户的作业保留了比通常需要的更多的资源——允许它们处理负载峰值和故障转移——并且可以回收这些大部分未使用的资源来运行批处理作业。容器提供了使这成为可能的资源管理工具,以及强大的内核级资源隔离,以防止进程相互干扰。我们通过在 Borg 开发的同时增强 Linux 容器来实现这一点。但是,隔离并不完美:容器无法防止对操作系统内核不管理的资源的干扰,
现代容器不仅仅是一种隔离机制:它还包括一个映像——构成在容器内运行的应用程序的文件。在 Google 内部,MPM(Midas Package Manager)用于构建和部署容器镜像。在 Docker 守护进程和 Docker 镜像注册表之间可以找到隔离机制和 MPM 包之间相同的共生关系。在本文的其余部分,我们使用容器这个词来涵盖这两个方面:运行时隔离和镜像。
面向应用的基础设施
随着时间的推移,很明显容器化的好处不仅仅是提高利用率。容器化将数据中心从面向机器转变为面向应用。本节讨论两个示例:
• 容器封装应用程序环境,从应用程序开发人员和部署基础设施中抽象出机器和操作系统的许多细节。
• 由于精心设计的容器和容器映像仅限于单个应用程序,因此管理容器意味着管理应用程序而不是机器。管理 API 从面向机器到面向应用程序的这种转变极大地改进了应用程序部署和内省。
应用环境
内核中 cgroup、chroot 和命名空间设施的最初目的是保护应用程序免受嘈杂、讨厌和凌乱的邻居的影响。将这些与容器映像相结合创建了一个抽象,该抽象还将应用程序与其运行的(异构)操作系统隔离开来。镜像和操作系统的这种解耦使得在开发和生产中提供相同的部署环境成为可能,这反过来又通过减少不一致和摩擦来提高部署可靠性并加快开发速度。
使这种抽象工作的关键是拥有一个密封的容器映像,它可以将应用程序的几乎所有依赖项封装到可以部署到容器中的包中。如果正确执行此操作,则唯一的本地外部依赖项将位于 Linux 内核系统调用接口上。虽然这个有限的接口极大地提高了镜像的可移植性,但它并不完美:应用程序仍然可以暴露在 OS 接口中,特别是在由套接字选项/proc
、 和 ioctl 调用的参数暴露的广阔表面区域中。我们希望诸如开放容器倡议 ( https://www.opencontainers.org/ )等正在进行的努力将进一步阐明容器抽象的表面积。
尽管如此,容器提供的隔离和依赖最小化在谷歌被证明是非常有效的,容器已经成为谷歌基础设施支持的唯一可运行实体。一个后果是,谷歌在任何时候都只在其整个机器群中部署了少量操作系统版本,并且只需要少量人员来维护它们并推出新版本。
有很多方法可以实现这些密封镜像。在 Borg 中,程序二进制文件在构建时静态链接到公司范围存储库中托管的已知良好库版本。5即便如此,Borg 容器镜像并不像它本来的那样密封:应用程序共享一个所谓的基础镜像,该镜像在机器上安装一次,而不是打包在每个容器中。此基本映像包含诸如 tar 和 libc 库之类的实用程序,因此升级到基本映像会影响正在运行的应用程序,并且偶尔会成为重要的麻烦来源。
更现代的容器镜像格式(如 Docker 和 ACI)进一步强化了这种抽象,并通过消除隐含的主机操作系统依赖项并要求显式用户命令在容器之间共享镜像数据,从而更接近密封理想。
容器作为管理单元
围绕容器而不是机器构建管理 API 将数据中心的“主键”从机器转移到应用程序。这有很多好处:(1)它使应用程序开发人员和运营团队免于担心机器和操作系统的具体细节;(2) 它为基础设施团队提供了推出新硬件和升级操作系统的灵活性,同时将对运行的应用程序及其开发人员的影响降至最低;(3) 它将管理系统收集的遥测数据(例如 CPU 和内存使用率等指标)与应用程序而非机器相关联,这显着改善了应用程序监控和自省,尤其是在扩展、机器故障或维护导致应用程序实例时移动。
容器提供了方便的点来注册通用 API,这些 API 支持管理系统和应用程序之间的信息流,而无需了解对方实现的细节。在 Borg 中,这个 API 是一系列附加到每个容器的 HTTP 端点。例如,/healthz
端点向协调器报告应用程序运行状况。当检测到不健康的应用程序时,它会自动终止并重新启动。这种自我修复是可靠分布式系统的关键构建块。(Kubernetes 提供了类似的功能;健康检查使用用户指定的 HTTP 端点或在容器内运行的 exec 命令。)
附加信息可以由容器提供或为容器提供并显示在各种用户界面中。例如,Borg 应用程序可以提供可以动态更新的简单文本状态消息,而 Kubernetes 提供存储在每个对象元数据中的键值注释,可用于传达应用程序结构。此类注释可由容器本身或管理系统中的其他参与者设置(例如,推出容器更新版本的过程)。
在另一个方向,容器管理系统可以将信息传递到容器中,例如资源限制、用于传播到日志记录和监控的容器元数据(例如,用户名、作业名称、身份)以及提供正常终止警告的通知提前维护节点。
容器还可以通过其他方式提供面向应用程序的监控:例如,Linux 内核 cgroup 提供有关应用程序的资源利用率数据,并且可以通过使用 HTTP API 导出的自定义指标进行扩展,如前所述。这些数据支持开发通用工具,如自动缩放器或 cAdvisor 3,它们可以在不了解每个应用程序细节的情况下记录和使用指标。因为容器就是应用程序,所以不需要(解)多路复用来自在物理机或虚拟机内运行的多个应用程序的信号。这更简单、更健壮,并且允许对指标和日志进行更细粒度的报告和控制。将此与必须ssh
进入机器运行进行比较top
。虽然开发人员可以ssh
进入他们的容器,他们很少需要。
监控只是一个例子。面向应用程序的转变在整个管理基础架构中产生了连锁反应。我们的负载平衡器不会跨机器平衡流量;它们在应用程序实例之间保持平衡。日志由应用程序而不是机器作为键控,因此可以轻松地跨实例收集和聚合它们,而不会受到多个应用程序或系统操作的污染。我们可以检测应用程序故障并更容易地归因故障原因,而无需将它们与机器级信号分开。从根本上说,由于容器管理器管理的实例身份与应用程序开发人员期望的实例身份完全一致,因此更容易构建、管理和调试应用程序。
最后,尽管到目前为止我们专注于与容器 1:1 的应用程序,但实际上我们使用在同一台机器上共同调度的嵌套容器:最外层的容器提供资源池;内部提供部署隔离。在 Borg 中,最外层的容器称为资源分配,或alloc;在 Kubernetes 中,它被称为pod。Borg 还允许顶级应用程序容器在 alloc 之外运行;这是造成很多不便的根源,因此 Kubernetes 将事物规范化并始终在顶级 pod 内运行应用程序容器,即使 pod 包含单个容器。
一个常见的使用模式是让一个 pod 来保存一个复杂应用程序的实例。应用程序的主要部分位于其中一个子容器中,其他容器运行支持功能,例如日志轮换或点击日志卸载到分布式文件系统。与将功能组合到单个二进制文件中相比,这使得不同团队可以轻松开发不同的功能块,并且提高了健壮性(即使主应用程序被楔入,卸载也会继续)、可组合性(很容易添加新的功能)小的支持服务,因为它运行在自己的容器提供的私有执行环境中),以及细粒度的资源隔离(每个运行在自己的资源中,所以日志系统不能饿死主应用程序,反之亦然)。
编排是开始,而不是结束
最初的 Borg 系统可以在共享机器上运行不同的工作负载,以提高资源利用率。然而,Borg 生态系统中支持服务的快速发展表明,容器管理本身只是用于开发和管理可靠分布式系统的环境的开始。在 Borg 内部、之上和周围构建了许多不同的系统,以改进 Borg 提供的基本容器管理服务。以下部分列表给出了它们的范围和种类的概念:
• 命名和服务发现(Borg Name Service,或 BNS)。
• 主选举,使用Chubby。2
• 应用感知负载平衡。
• 水平(实例数量)和垂直(实例大小)自动缩放。
• 管理新二进制文件和配置数据的仔细部署的推出工具。
• 工作流工具(例如,允许运行在阶段之间具有相互依赖性的多作业分析管道)。
• 监控工具以收集有关容器的信息、聚合信息、将其显示在仪表板上,并使用它来触发警报。
这些服务是有机构建的,以解决应用程序团队遇到的问题。成功的那些被挑选出来,被广泛采用,并使其他开发人员的生活更轻松。不幸的是,这些工具通常选择特殊的 API、约定(例如文件位置)和 Borg 集成的深度。一个不希望的副作用是增加了在 Borg 生态系统中部署应用程序的复杂性。
Kubernetes 试图通过对其 API 采取一致的方法来避免这种增加的复杂性。例如,每个 Kubernetes 对象在其描述中都有三个基本字段:Object Metadata
、Specification
(或Spec
)和Status
。
的Object Metadata
是系统中的所有对象一样; 它包含诸如对象名称、UID(唯一标识符)、对象版本号(用于乐观并发控制)和标签(键值对,见下文)等信息。和 的内容因对象类型Spec
而Status
异,但它们的概念没有:Spec
用于描述对象的期望状态,而Status
提供有关对象当前状态的只读信息。
这种统一的 API 提供了许多好处。具体来说,学习系统更简单:类似的信息适用于所有对象。此外,编写适用于所有对象的通用工具更简单,从而能够开发一致的用户体验。向 Borg 和 Omega 学习,Kubernetes 由一组可组合的构建块构建而成,用户可以轻松扩展这些构建块。通用的 API 和对象元数据结构使这变得更加容易。例如,pod API 可供人员、内部 Kubernetes 组件和外部自动化工具使用。为了进一步保持这种一致性,Kubernetes 正在扩展,使用户能够动态添加自己的 API,以及 Kubernetes 的核心功能。
一致性也是通过 Kubernetes API 中的解耦来实现的。API 组件之间的关注点分离意味着更高级别的服务都共享相同的公共基本构建块。一个很好的例子是 Kubernetes 副本控制器与其水平自动扩展系统之间的分离。复制控制器确保存在给定角色(例如,“前端”)所需数量的 pod。反过来,自动缩放器依赖此功能并简单地调整所需的 pod 数量,而无需担心如何创建或删除这些 pod。Autoscaler 实现可以专注于需求和使用预测,而忽略如何实现其决策的细节。
解耦确保多个相关但不同的组件共享相似的外观。例如,Kubernetes 具有三种不同形式的复制 pod:
• ReplicationController
:永远运行的复制容器(例如,Web 服务器)。
• DaemonSet
:确保集群中每个节点上的单个实例(例如,日志代理)。
• Job
:一个运行到完成控制器,知道如何从头到尾运行(可能是并行化的)批处理作业。
不管策略上有什么不同,所有这三个控制器都依赖于公共 pod 对象来指定它们希望运行的容器。
一致性也是通过不同 Kubernetes 组件的通用设计模式来实现的。协调控制器循环的想法在整个 Borg、Omega 和 Kubernetes 中共享,以提高系统的弹性:它将所需状态(例如,应该有多少 pod 与标签选择器查询匹配)与观察到的状态(数量它可以找到的此类 Pod 的数量),并采取行动来收敛观察到的和期望的状态。因为所有动作都基于观察而不是状态图,所以协调循环对故障和扰动具有鲁棒性:当控制器出现故障或重新启动时,它只是从停止的地方开始。
将 Kubernetes 设计为微服务和小型控制循环的组合是通过编排进行控制的一个例子——通过组合协作的独立自主实体的效果来实现所需的紧急行为。与集中式编排系统相比,这是一种有意识的设计选择,集中式编排系统一开始可能更容易构建,但随着时间的推移往往会变得脆弱和僵化,尤其是在出现意外错误或状态变化的情况下。
需要避免的事情
在开发这些系统,我们已经学会了几乎同样多的东西不能做,因为这是值得做的事情的想法。我们在此展示其中的一些,希望其他人可以专注于犯新的错误,而不是重蹈我们的覆辙。
不要让容器系统管理端口号
在 Borg 机器上运行的所有容器共享主机的 IP 地址,因此 Borg 为容器分配唯一的端口号作为调度过程的一部分。容器在移动到新机器时和(有时)在同一台机器上重新启动时,将获得一个新的端口号。这意味着 DNS(域名系统)等传统网络服务必须被自制版本取代;服务客户端不知道先验分配给服务的端口号,因此必须被告知;端口号不能嵌入到 URL 中,需要基于名称的重定向机制;依赖于简单 IP 地址的工具需要重写以处理 IP:port 对。
从我们在 Borg 的经验中学习,我们决定 Kubernetes 将为每个 pod 分配一个 IP 地址,从而使网络身份(IP 地址)与应用程序身份保持一致。这使得在 Kubernetes 上运行现成的软件变得更加容易:应用程序可以自由地使用静态众所周知的端口(例如,80 用于 HTTP 流量),并且现有的、熟悉的工具可用于诸如网络分段、带宽之类的事情节流和管理。所有流行的云平台都提供支持 IP-per-pod 的网络底层;在裸机上,可以使用 SDN(软件定义网络)覆盖或配置 L3 路由来处理每台机器的多个 IP。
不要只给容器编号:给它们贴标签
如果您允许用户轻松创建容器,他们往往会创建大量容器,并且很快需要一种对它们进行分组和组织的方法。Borg 提供工作来分组相同的任务(它的容器名称)。作业是一个或多个相同任务的紧凑向量,从零开始按顺序索引。这提供了很大的力量并且简单明了,但随着时间的推移,我们开始后悔它的僵化。例如,当一个任务死掉并且必须在另一台机器上重新启动时,任务向量中的同一个槽必须做双重任务:识别新副本并指向旧副本以防需要调试。当向量中间的任务退出时,向量最终会出现漏洞。该向量使得在 Borg 之上的层中支持跨越多个集群的作业变得非常困难。在 Borg 的作业更新语义(通常在进行滚动升级时按索引顺序重新启动任务)和应用程序对任务索引的使用(例如,跨任务对数据集进行分片或分区):如果应用程序使用基于任务索引的范围分片,Borg 的重启策略会导致数据不可用,因为它会取消相邻的任务。Borg 也没有提供简单的方法来将与应用程序相关的元数据添加到作业中,例如角色(例如,“前端”)或推出状态(例如,“金丝雀”),因此人们将此信息编码为他们使用的作业名称进行解码正则表达式。
相比之下,Kubernetes 主要使用标签来标识容器组。标签是包含有助于识别对象的信息的键/值对。一个 pod 可能有标签role=frontend
和stage=production
,表明这个容器作为一个生产前端实例。标签可以由自动化工具或用户动态添加、删除和修改,不同的团队可以在很大程度上独立管理自己的标签。对象集由标签选择器定义(例如,stage==production && role==frontend
)。集合可以重叠,一个对象可以在多个集合中,因此标签本质上比明确的对象列表或简单的静态属性更灵活。因为集合是由动态查询定义的,所以可以随时创建新的集合。标签选择器是Kubernetes中的分组机制,它定义了可以跨越多个实体的所有管理操作的范围。
即使在知道集合中任务的身份有帮助的情况下(例如,对于静态角色分配和工作分区或分片),也可以使用适当的 per-pod 标签来重现任务索引的效果,尽管它是应用程序(或 Kubernetes 外部的其他一些管理系统)负责提供此类标签。标签和标签选择器提供了一种通用机制,可以两全其美。
小心所有权
在 Borg 中,任务并不是独立于工作而存在的。创建工作创建它的任务;这些任务永远与该特定作业相关联,删除作业会删除这些任务。这很方便,但有一个很大的缺点:因为只有一种分组机制,需要处理所有用例。例如,作业必须存储仅对服务或批处理作业有意义但不能同时对两者有意义的参数,并且当作业抽象不处理用例时(例如,DaemonSet
将单个 pod 复制到所有节点),用户必须开发变通方法在集群中)。
在 Kubernetes 中,诸如复制控制器之类的 pod 生命周期管理组件使用标签选择器确定它们负责哪些 pod,因此多个控制器可能认为它们对单个 pod 具有管辖权。通过适当的配置选择来防止此类冲突很重要。但是标签的灵活性具有补偿优势——例如,控制器和 Pod 的分离意味着可以“孤立”和“采用”容器。考虑一个负载平衡服务,它使用标签选择器来识别要向其发送流量的一组 pod。如果这些 Pod 之一开始出现行为异常,则可以通过删除一个或多个导致 Kubernetes服务将其作为目标的标签来隔离该 Pod 的服务请求负载均衡器。Pod 不再提供流量,但它会保持运行状态并且可以就地调试。与此同时,管理实现服务的 pod 的复制控制器会自动为行为不端的 pod 创建一个替换 pod。
不要暴露原始状态
Borg、Omega 和 Kubernetes 之间的主要区别在于它们的 API 架构。Borgmaster 是一个整体组件,它知道每个API 操作的语义。它包含集群管理逻辑,例如作业、任务和机器的状态机;它运行基于 Paxos 的复制存储系统,用于记录 master 的状态。相比之下,Omega 除了 store 没有中心化组件,它只保存被动状态信息并强制执行乐观并发控制:所有逻辑和语义都被推送到 store 的客户端,客户端直接读取和写入 store 内容。在实践中,每个 Omega 组件都使用相同的客户端库进行存储,该库执行数据结构的打包/解包、重试并强制执行语义一致性。
Kubernetes 选择了一个中间立场,它提供了 Omega 组件化架构的灵活性和可扩展性,同时强制执行系统范围的不变量、策略和数据转换。它通过一个集中式 API 服务器强制所有商店访问来实现这一点,该服务器隐藏了商店实现的细节并提供对象验证、默认设置和版本控制服务。与 Omega 一样,客户端组件彼此分离,可以独立演化或替换(这在开源环境中尤其重要),但集中化可以轻松实施通用语义、不变量和策略。
一些开放的、困难的问题
即使拥有多年的容器管理经验,我们仍然觉得有许多问题我们仍然没有很好的答案。本节描述了几个特别棘手的问题,希望能促进讨论和解决方案。
配置
在我们面临的所有问题中,最耗费脑力、墨水和代码的问题与管理配置有关——提供给应用程序的一组值,而不是硬编码到它们中。事实上,我们本可以把整篇文章都放在这个主题上,而且还有更多的话要说。以下是一些重点。
首先,应用程序配置成为实现容器管理系统(尚未)做的所有事情的全部位置。在博格的历史中,这包括:
• 减少样板文件(例如,适用于工作负载的默认任务重启策略,例如服务或批处理作业)。
• 调整和验证应用程序参数和命令行标志。
• 为缺少 API 抽象(例如包(镜像)管理)实施变通方法。
• 应用程序配置模板库。
• 发布管理工具。
• 镜像版本规范。
为了应对这些类型的需求,配置管理系统倾向于发明一种特定领域的配置语言,它(最终)成为图灵完备的,从对配置中的数据执行计算的愿望开始(例如,调整配置中的数据量)内存以作为服务中分片数量的函数为服务器提供)。结果是人们试图通过消除应用程序源代码中的硬编码参数来避免出现那种难以理解的“配置就是代码”。它不会降低操作复杂性或使配置更易于调试或更改;它只是将计算从真正的编程语言转移到特定领域的语言,该语言通常具有较弱的开发工具(例如,调试器、单元测试框架等)。
我们认为最有效的方法是接受这种需求,接受编程配置的必然性,并在计算和数据之间保持清晰的分离。表示数据的语言应该是一种简单的、纯数据格式,例如 JSON 或 YAML,并且应该使用真正的编程语言来对这些数据进行编程修改,这种语言具有易于理解的语义和良好的工具。有趣的是,在前端开发的不同领域中可以看到这种相同的计算和数据分离,Angular 等框架在标记(数据)和 JavaScript(计算)世界之间保持清晰的分离。
依赖管理
建立一个服务通常也意味着建立一系列相关的服务(监控、存储、CI/CD 等)。如果一个应用程序依赖于其他应用程序,那么集群管理系统自动实例化这些依赖项(以及它们可能具有的任何传递依赖项)不是很好吗?
更复杂的是,实例化依赖项很少像开始一个新副本那么简单——例如,它可能需要注册为现有服务(例如 Bigtable 即服务)的消费者,并在整个过程中传递身份验证、授权和计费信息。那些传递依赖。然而,几乎没有系统会捕获、维护或公开这种依赖信息,因此即使在基础设施级别自动化常见情况也几乎是不可能的。对用户而言,启用新应用程序仍然很复杂,这使得开发人员更难构建新服务,并且经常导致未遵循最新的最佳实践,从而影响结果服务的可靠性。
一个标准问题是,如果依赖信息是手动提供的,则很难使其保持最新,同时尝试自动确定它(例如,通过跟踪访问)无法捕获理解结果所需的语义信息。(是否必须访问该实例,或者任何实例都已足够?)取得进展的一种可能方法是要求应用程序枚举它所依赖的服务,并让基础设施拒绝允许访问任何其他服务. (我们在构建系统中为编译器导入执行此操作。1)动机是使基础设施能够做有用的事情作为回报,例如自动设置、身份验证和连接。
不幸的是,表达、分析和使用系统依赖项的系统的感知复杂性太高,因此它们尚未添加到主流容器管理系统中。我们仍然希望 Kubernetes 成为可以构建此类工具的平台,但这样做仍然是一个开放的挑战。
结论
十年的构建容器管理系统的经验教会了我们很多东西,我们已经将其中的许多经验嵌入到谷歌最新的容器管理系统 Kubernetes 中。它的目标是建立在容器的能力之上,以显着提高程序员的工作效率并简化手动和自动系统管理。我们希望您能与我们一起扩展和改进它。
References
1. Bazel: {fast, correct}—choose two; http://bazel.io.
2. Burrows, M. 2006. The Chubby lock service for loosely coupled distributed systems. Symposium on Operating System Design and Implementation (OSDI), Seattle, WA.
3. cAdvisor; https://github.com/google/cadvisor.
4. Kubernetes; http://kubernetes.io/.
5. Metz, C. 2015. Google is 2 billion lines of code—and it's all in one place. Wired (September); http://www.wired.com/2015/09/google-2-billion-lines-codeand-one-place/.
6. Schwarzkopf, M., Konwinski, A., Abd-el-Malek, M., Wilkes, J. 2013. Omega: flexible, scalable schedulers for large compute clusters. European Conference on Computer Systems (EuroSys), Prague, Czech Republic.
7. Verma, A., Pedrosa, L., Korupolu, M. R., Oppenheimer, D., Tune, E., Wilkes, J. 2015. Large-scale cluster management at Google with Borg. European Conference on Computer Systems (EuroSys), Bordeaux, France.
Brendan Burns (@brendandburns) is a software engineer at Google, where he co-founded the Kubernetes project. He received his Ph.D. from the University of Massachusetts Amherst in 2007. Prior to working on Kubernetes and cloud, he worked on low-latency indexing for Google's web-search infrastructure.
Brian Grant is a software engineer at Google. He was previously a technical lead of Borg and founder of the Omega project and is now design lead of Kubernetes.
David Oppenheimer is a software engineer at Google and a tech lead on the Kubernetes project. He received a PhD from UC Berkeley in 2005 and joined Google in 2007, where he was a tech lead on the Borg and Omega cluster-management systems prior to Kubernetes.
Eric Brewer is VP Infrastructure at Google and a professor at UC Berkeley, where he pioneered scalable servers and elastic infrastructure.
John Wilkes has been working on cluster management and infrastructure services at Google since 2008. Before that, he spent time at HP Labs, becoming an HP and ACM Fellow in 2002. He is interested in far too many aspects of distributed systems, but a recurring theme has been technologies that allow systems to manage themselves. In his spare time he continues, stubbornly, trying to learn how to blow glass.
微信
支付宝