企业🤖AI Agent构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### :-: **Borg Omega and kubernetes**。 最近新起了对于容器技术的广泛兴趣,在大型的Linux容器管理上,我们google已经有超过十年的经验,并且已经构建过3个不同的容器管理系统,每一个系统都深刻的影响到了他的继任者,尽管他们处于不同的目的开发,这篇文章描述了我们在开发过程中以及在操作中学习经验。<br />   第一个由google开发管理的容器系统我们内部称为Borg,他被构建为管理长时运行服务,以及处理batch job。这两个任务之前被两个系统分开处理,一个叫babysister,一个叫Globe Work Queue。后者的架构强烈的影响了Borg,但主要关注点是batch job,两者都早于Linux control group.Borg在这两种类型的应用程序之间共享机器,以提高资源利用率并从而降低成本,之所以进行这种共享,是因为Linux内核中的容器支持。(事实上,大多数Kernel的容器代码都是google贡献的)。这在面向用户的延迟敏感性任务与CPU需求型batch处理上开启了更好的隔离。      随着越来越多的应用在Borg之上被构建,我们的应用团队与基础设置团队开发了一系列的工具与服务生态,这些系统提供了用于配置和更新作业的机制,预测资源需求,动态将配置文件推送到运行的作业,服务发现与负载均衡,自动伸缩,机器生命周期管理,配额管理,以及其他许多。这些生态的发展被来自于google内部不同的团队所驱动。结果形成了一个异构的,ad-hoc的一个系统,Borg用户不得不与之交互与配置。采用了几种不同的配置语言与处理过程。因为Borg的规模是如此之大,功能又广,健壮性又高因此它仍然是google内部最主要的容器。<br /> Omega,borg的后代,处于改变Borg软件生态系统的目地,他应用了许多Borg上被证明成功了的模式。但他是从头开始构建的,具有更一致,更原则的体系结构。omega将集群的状态存储在基于Paxos的集中式面相事务的存储中,该存储由控制集群平面的不同部分(例如调度程序访问),使用乐观并发控制来处理偶尔的冲突,这种解耦使得Borgmaster的功能分解为独立的组件并扮演为一个peer。而不是把每一个变化都汇集到整体的,集中化的master中。许多Omega的创新都被整合到了Borg中(包括多调度器)。<br />   第三代googe开发的容器管理系统是kubernetes。它是在外部开发人员开始对Linux容器感兴趣的环境中构思和开发的。google开发了一项销售公共云基础设置的业务,该业务不断增长,与Borg和Omega形成鲜明地比的,kuberntes是开源的,后两者完全作为google内部系统开发。像omega,kubernets的核心是共享持久存储,组件监视相关对象的更改,对比omega,后者直接将存储暴露给受信任的控制平面组件。kubernetes里的状态只能通过一个指定的REST API去访问,验证,semantics, 与策略。支持多样化的客户端,更重要的是,更重要的是,Kubernetes的开发更加关注开发人员编写在集群中运行的应用程序的体验:其主要设计目标是使其易于部署和管理复杂的分布式系统,同时也使得容器的利用率提高。 <br /> 这篇文章主要讲述了google从Borg到Kubernetes的旅途以及从中获取到的经验。 <br /> ## **CONTAINERS** 早先时候,第一代容器仅仅提供了对于root文件系统的隔离(通过chroot),以及freeBSD jails扩展到了额外的namespace比如process IDs。Solaris 之后探索并开创了许多其他增强的功能。Linux控制集(Cgroup)采纳了许多这样的想法,并且一直发展持续到了今日。<br /> 容器提供的资源隔离使google的利用率明显高于行业规范。例如,Borg使用容器在同一台物理机器将延迟敏感性,面向对象用户与Batch jobs置于一起。面向用户的作业保留了比通常所需更多的资源,从而使它们能够处理负载高峰和故障转移,并且可以回收这些最未被使用的资源来运行批处理作业。容器提供了资源管理的工具使得这成为了可能。以及强大的内核级资源隔离,以防止进程相互干扰。<br /> 我们通过Borg的开发与增强Linux容器来达到这一点。隔离并不完美,容器无法阻止操作系统内核无法管理的资源受到干扰。例如三级处理器缓存与内存宽带。容器需要被另外的安全层支持(比如:虚拟机)以防止在云中发现的各种恶意行为。 <br />现代化的容器不仅仅是一个隔离机制。他同样包括了一个Image-一个在容器内部组成应用程序的文件,在google,MPM(Midas Package Manager)被用来构建和部署容器镜像。隔离机制与MPM之间的共生关系与Docker daemon和Docker image registry相似。 在这篇文章的剩余部分我们使用容器来包含这诸多方面:运行时隔离与镜像。 <br /> ## **APPLICATION-ORIENTED INFRASTRUCTURE:** 随着时间的推移,集装箱化的好处越来越明显,不仅仅是提高利用率。容器话将面向机器的方向转变为面向应用程序的方向。本节讨论了两个实例: ●容器封装应用程序环境,从应用程序的开发与基础设施的部署中抽象出了许多机器与操作系统的细节。 ●因为设计良好的容器和容器映像的范围仅限于单个应用程序,许多容器意味着管理应用而不是机器,这种从面向机器到面向应用程序的管理API的移动极大的改善了应用程序的部署与自检。<br /><br /> ## **应用程序环境** 内核中的cgroup,chroot,和namespace的功能最初是为了保护应用程序不受干扰,以及其他不良的影响。将他们与容器镜像结合在一起创建了一个抽象,该抽象也将应用程序与(异构)运行于其上的操作系统隔离开来。映像和OS的这种解耦使得可以在开发和生产中提供相同的部署环境,从而通过减少不一致和摩擦来提高部署可靠性并加快开发速度。实现这种抽象的关键是有一个密封的容器映像,它可以将应用程序的几乎所有依赖项封装到可以部署到容器中的包中。如果这被正确的操作了,那么剩下的外部依赖就只是本地Linux内核的系统调用接口了。尽管这种接口的限制性极大的提高了容器的可移植性,但他并不完美,应用程序仍然会暴露在操作系统混乱的接口中。特别是套接字选项暴露的大片区域,/proc,以及对于ioctl的参数调用,我们的目标是不断的努力使得开发容器计划以后会统一容器抽象的表面区域。 <br />  这里有许多的方法实现密闭的镜像。在Borg里面,程序的二进制文件在构建静态链接时链接到公司范围内的有效版本库中。即使如此,Borg的容器镜像并不像本来的那样封闭。应用程序共享一个所谓的基本映像,该映像只在机器上安装一次,而不是打包在每个容器中。这个基础镜像包含例如tar与libc库文件。因此,对基本镜像的升级可能会影响运行的应用程序,有时还会造成很大的麻烦。 <br />  许多现代化的容器镜像格式例如Docker与ACI,进一步加强了这种抽象,并通过消除隐式的主机操作系统依赖和要求显式的用户命令来共享容器之间的映像数据,使之更接近于密封的理想状态(More modern container image formats such as Docker and ACI harden this abstraction further and get closer to the hermetic ideal by eliminating implicit host OS dependencies and requiring an explicit user command to share image data between containers.)。(这一句话就是一段。。) <br /> ## **容器作为管理单元** 围绕容器而不是机器构建管理API,将数据中心的“主键”从机器转移到应用程序。这有许多好处,它使应用程序开发人员和操作团队不必担心机器和操作系统的特定细节;它使基础架构团队能够灵活地推出新硬件和升级操作系统,而对运行中的应用程序及其开发人员的影响最小; 它将管理系统收集的遥测数据(例如CPU和内存使用等指标)与应用程序而不是机器联系起来, 这极大地改善了应用程序的监视和自检。特别是在伸缩性,机器故障,或者维护造成的应用程序实例移动。容器提供了方便的点去注册通用API,在系统管理与应用程序之间开启信息的流动而不用知道太多关于其他特别的实现。在Borg,这个API是一系列附在每一个容器上的HTTP端点。例如 /healthz 端点报告应用程序的状况给调度器。当检测到一个不健康的应用程序时,它自动终结并重启它。这种自修复是可靠分布式系统的关键构建点。(kubernetes提供相似的功能,健康检查采用一个用户指定的HTTP端点或者exec命令在容器里运行。) <br /> 额外的信息可以被容器提供或者为容器提供并显示各种用户接口。例如:Borg提供一种动态更新的简单的文字状态信息。kubernetes提供存储在每一个对象的元数据下的备注,用于传达应用程序结构。这种备注可以被容器自身或者管理系统中的其他参与者设置。(例如,该过程推出了容器的更新版本。) <br />另一方面,容器管理可以将信息传递到容器比如资源限制。容器元数据,用过传播到日志记录和监控,(例如,用户名,job那么,身份。)以及在节点维护之前提供正常终止警告的通知。 <br />  容器还可以通过其他方式提供面向应用程序的监视,Linux Kernel cgroup 提供关于应该用程序的资源利用率数据。并且这些可以通过使用HTTP API导出的自定义指标进行扩展,如前面描述的那样,利用这些数据,可以开发通用工具,例如自动缩放器或cAdvisor3,这些工具可以记录和使用指标,而无需了解每个应用程序的细节。因为容器就是应用程序,there is no need to (de)multiplex signals from multiple applications running inside a physical or virtual machine.。(无需对来自物理或虚拟机中运行的多个应用程序的信号进行(解复用)。)这更简单,更强大,并允许更精细的报告控制指标与日志。相比于通过ssh登录到一台机器上运行top,尽管开发人员有可能需要ssh进他们的容器中,但他们很少需要这样做。 <br />  监视方式是一个例子,面向应用程序的转变对整个管理基础架构都有连锁反应。我们的负载均衡并不能平衡计算机之间的流量。他们在应用程序的实例间保持平衡, 日志由应用程序键入,而不是机器,因此可以轻松地跨实例收集和聚合它们,而不会受到多个应用程序或系统操作的污染。We can detect application failures and more readily ascribe failure causes without having to disentangle them from machine-level signals.从根本上讲,由于容器管理器管理的实例的身份与应用程序开发人员期望的实例的身份完全一致,这使得构建管理,调试,都变得更加容易。 <br />  最后,尽管到目前为止我们将注意力们集中在应用程序域容器比例在1:1上,in reality we use nested containers that are co-scheduled on the same machine:(实际上,我们使用在同一台机器上共同调度的嵌套容器。)最外层提供有一个资源池,内部提供部署隔离,在Borg,最外层的容器被称作一个资源分配,or alloc,在kubernetes里,这被称作pod,Borg同样允许高层的应用程序容器运行在allocs外面。这同样带来了很多的不方便,因此Kubernetes规范化了事情并总是让应用程序容器运行在顶层的pod中,即使这个pod只包含一个容器。 <br />  对于pod来说一个常用的使用模式是保存一个复杂的应用程序实例。应用程序的主要部分位于一个字容器中。其他子容器则运行支持功能比如日志切割或者将日志卸载到分布式系统中。与将功能组合到单个二进制文件相比,这使得不同的团队开发不同的功能时变得更加容易。同时这也提高了健壮性,(即使主应用层序被wedged了卸载仍然会继续),可组合性,(可以很轻松的添加一个新的小型支持服务),因为这个操作是在由容器自身提供的私有环境当中,和细粒度的资源隔离(每一个都运行它自己资源,每个应用程序都在自己的资源中运行,因此日志记录系统不会饿死主应用程序,反之亦然)<br /> <br /> ## **Orchestration is the beginning, not the end(编排是开始,而不是结束),** 原始的Borg系统在共享的机器上运行不同的工作负载成为可能,这提高了资源利用率。同时迅速发展的Borg生态系统支持服务,但是,表明容器管理本身仅仅是开发和管理可靠的分布式系统的环境的开始。在Borg上和周围建立了许多不同的系统,以改进Borg提供的基本容器管理服务。以下列出了它们大致的范围与种类。 ● 命名与服务发现(Borg命名服务,或者BNS)。 ● Master选定,使用Chubby。 ● 应用感知负载平衡。 ● 水平(实例数量)和垂直(实例大小)自动缩放。 ● 推出新的工具管理谨慎的部署新的二进制文件与配置数据。 ● 工作流程工具,(允许在相互依赖的阶段之间运行多作业的分析管道。) ● 监视工具收集容器信息,聚合,呈现在控制面板上,同时触发警告。 <br />  这些服务是有机构建的,旨在解决应用程序团队遇到的问题。成功的版本被采纳,被广泛使用,并使其他开发人员的生活更加轻松,不幸的是,这些工具通常选择特殊的api,约定(如文件位置),Borg整合的深度,意外的副作用是增加了在Borg生态系统中部署应用程序的复杂性。Kubernetes试图通过对其API采用一致​​的方法来避免这种增加的复杂性。例如,每一个kubernetes目标有三个基础字段的描述:对象元数据,规范与状态。 <br />  系统中所有对象的对象元数据都相同;它包含对象名称、UID(唯一标识符)、对象版本号(用于乐观并发控制)、和标签(键值对,请参见下文)。规格和状态的内容因对象类型而异,但他们的概念并不是:Spec用于描述对象的所需状态,而Status提供有关对象当前状态的只读信息。 <br />  统一的API提供了许多的好处,学习系统更简单,相似的信息应用到所有的对象上,编写跨所有对象的通用工具更加简单了。同时这也提升了用户体验。从Borg与Omega当中学习,Kubernetes是由一组可组合的构建基块构建的,用户可以轻松地对其进行扩展。通用的API和对象元数据结构使这一过程变得更加容易。 例如,人们可以使用pod API,kubernetes内部组件,以及外部的自动化工具,为了对一致性更进一步,kubernetes将会扩展到开启动态的添加用户自己的API。alongside the core Kubernetes functionality。还可以通过Kubernetes API中的解耦来实现一致性。API组件之间分离的关注点是更高级别的服务都共享相同的公共基本构建块。这方面分离的一个例子是Kubernetes的replication 控制器与水平自动缩放系统。一个复制控制器确保给定角色的现有的pods数量等于所需的(比如前端)。反过来,自动扩缩器,依靠此功能,只需要简单的调整所需要的pods数量。而不动担心pod如何被创建于删除。自动缩放其道实施可以着重于需求和使用情况的预测。以及忽略如何去实施决策的细节。 <br />  解耦确保多个相互关联却不同的组件共享一个相似的外观,例如,kubernetes具有三种不同形式的复制pod, ReplicationController:永久运行的复制容器。 DaemonSet:在集群上确保每一个节点的单一实例。 Job:一个直到运行完成的控制器,知道如何从运行从开始到结束(可能是并行的)。 <br />  尽管是三种不同的策略,但这三种控制器依靠的都是公共的pod对象去指定他们要在哪些容器上运行。对于不同的kubernetes组件一致性同样通过公共设计模式实现。The idea of a reconciliation controller loop is shared throughout Borg, Omega, and Kubernetes to improve the resiliency of a system:相比于一个所需的状态,(例如:多少个pod应该与标签选择器查询匹配。)对比观察到的状态。(可以被找到的这样的pod数量。)并对所观察到的状态和所需状态采取行动。因为所有的行为都基于观察而不是状态图,调节循环对故障和扰动具有健壮性:当控制器故障或者重启时,他简单的又从上次失效的地方开始。Kubernetes设计为微服务和小型控制循环的结合,是通过编排进行控制的一个示例-通过组合写作的各个独立实体的效果来实现所需的紧急行为。预计集中式的编排系统相比,这是一个有意识的设计选择。刚开始时可能更容易构建,但随着时间的流逝会变得脆弱而僵化,尤其是在出现意外错误或状态变化的情况下。 ## <br />  **需要避免的事情** 在开发这些系统时,我们学到了几乎不值得做的事情,我们把它共享在这里,方便其他人能够犯新的错误而不是重复我们这些。   不要让容器系统管理端口号,所有在Borg上的容器系统都共享了主机的IP地址,因此Borg会在调度过程中为容器分配唯一的端口号,当容器移动到一个新的机器时他会得到一个新的端口号,(有时候)当他相同的机器上重启了,这意味着传统的网络服务比如DNS必须替换掉通过home-brew versions;service clients do not know the port number assigned to the service a priori and have to be told;(服务器并不知道分配给服务的端口号,这必须被告知),端口号不能被嵌入到URL中,需要name-base的重定向机制,需要重写依赖于简单IP地址的工具,以处理IP:端口对。 <br />  重Borg当中学到的,我们决定为每一个pod分配一个ip地址,从而使网络身份(IP地址)与应用程序身份保持一致。这使得在kubernetes上运行现成的软件更加容易了。应用程序免费使用静态的常见端口(例如80),and existing。熟悉的工具可以被用于网络分段,带宽限制与管理,所有流行的云平台都提供了启用IP-pod的网络基础。在裸机上,可以使用SDN(软件定义网络)覆盖或配置L3路由以再每台计算机上处理多个IP。 ## <br />  **不要给容器编号:给他们标签。** 如果你允许用户轻松的创建容器,他们倾向于其创建许多,然后就需要一种方法去组织与分类。Borg提供了jobs去分类相同的任务然后组织他们,从零开始顺序索引,这种方式简洁有力,但用了一段时间后就后悔了,例如,当一个任务死掉了之后必须在另一台机器上重启,这会使得任务槽中的位置重复,当在vector中间的任务退出时,the vector ends up with holes.The vector makes it very hard to support jobs that span multiple clusters in a layer above Borg. There are also insidious, unexpected interactions between Borg’s job-update semantics (which typically restarts tasks in index order when doing rolling upgrades) and an application’s use of the task index (e.g., to do sharding or partitioning of a dataset across the tasks):如果应用程序基于任务索引使用范围分片,Borg的重启策略可能会导致数据不可用。因为它会减少邻近的任务。Borg同样也没有提供简单的方法来添加与应用程序相关的元数据到作业中。比如角色(例如前端)。或者推出状态,因此人们将这些信息编码为工作名称,然后使用正则表达式对其进行解码。 <br />  相比起来,kubernetes首先使用标签去给容器分组。一个标签使用键值对它包含容器信息去帮助确认目标,一个pod可能有标签role=frontend 与 stage=production,指示此容器充当生产前端实例。标签可以动态添加。删除,然后通过自动化工具或者用户修改。而且不同的团队可以在很大程度上独立管理自己的标签。对象的集合由标签选择器定义,(e.g., stage==production && role==frontend).集可以重叠。一个对象可以有多个集合。因此,标签在本质上比对象的显式列表或简单的静态属性更灵活。因为集合是由动态查询定义的,可以在任何时候创建一个新的。Kubernetes的分组机制是标签选择器。并定义可以跨越多个实体的所有管理操作的范围。在某些情况下,能够定位一个任务所在的集合是有帮助的。例如,用于静态角色分配和工作分区或分片,可以使用适当的per-pod标签来重现任务索引的效果,尽管kubernetes有责任提供此类标签(或者Kubernetes外部的其他管理系统)。标签和标签选择器提供了一种通用机制,可以同时发挥两者的优点。 <br /> ## **Be careful with ownership(谨慎处理所有权)** 在Borg中,任务并不能独立于jobs独立存在。创建一个job便创建了一个task,这些任务永远与该特定工作关联在一起。删掉job便删掉了task。这很方便,但是却有一个很大的不足。以为这里只有一种分组机制,他需要处理所有用例,例如,作业必须存储仅对服务或批处理作业有意义的参数,但不能同时对两者有意义,当job的抽象并不能处理用例时,用户必须自己制定解决方案。例如:集群中一个daemonset复制单个pod到所有的节点上。 在Kubernetes中,pod生命周期管理组件例如replication控制器决定哪一个pod对使用标签选择器负责。因此多个控制器可能会认为他们对某个pod具有控制权限。通过适当的配置选择来防止这种冲突是很重要的。但是,标签的灵活性也有相应的优势,分离的控制器与pod意味着”orphan”与“adopt”是可能的。考虑一个负载均衡服务他使用一个标签选择器去标识要将流量发送到pod的集。如果其中的一个pod出现了异常。可以删除目标pod的标签来隔离该pod对于负载均衡的请求。这个pod就将不在负载traffic。但它将保留下来,可以在原地进行调试。与此同时,管理该服务的容器控制器会自动为不正常的pdo创建一个新的pod。 ## <br />**不要暴露原始状态:Don’t expose raw state** 在Borg,Omega,与kubernetes之间的一个关键不同点是他们的API架构,Borgmaster是一个独立组件,它知道每个API操作的语义。它包含集群管理逻辑,例如作业,任务和计算机的状态;并且运行基于Paxos的复制存储系统,该系统用于记录master的状态,相比之下,Omega除了存储之外没有集中组件,它仅保留被动状态信息并执行乐观并发控制:所有逻辑和语义都被推到存储的客户机中,这直接读写存储内容,在实际上,在实际上,每个Omega组件对存储使用相同的客户端库。这会对数据结构进行打包/解包、重试,并强制执行语义一致性。Kuberntes选择了一种中间立场,既提供了Omega组件化体系结构的灵活性和可伸缩性,又加强了系统范围的不变量,策略,和数据转换。它通过一个集中的API服务器来强制所有的存储访问,该服务器隐藏存储实现的细节,并为对象验证,默认值,和版本控制提供服务,就像在Omega中一样,客户端组件彼此分离,并且可以独立发展或替换(这在开源环境中尤其重要),但是集中化使得实施通用语义、不变量和策略变得容易。 ## <br />**一些开放的,困难的问题:** 即使在多年的容器管理经验之后,我们仍对于一些问题感到头疼。这一届我们描述几个特别棘手的问题。希望能够促进讨论宇宙哦啊到解决方案。<br /><br /> ## **配置** 在我们面临的所有问题当中,最耗费脑力、墨水和代码的问题都与管理配置有关,提供给应用程序的一组值,而不是硬编码到应用程序中。事实上,我们本可以用整篇文章来讨论这个问题,而且还有更多要说的。以下是一些亮点。First, application container-management system doesn’t (yet) do. Over the history of Borg this has included: becomes the catchall location for implementing all of the things that the (容器管理系统做不了的地方都变成了应用程序的配置去实现。)在Borg的历史上包括: ● Boilerplate reduction(减少样板):(例如,适用于工作负载的默认任务重启策略,例如服务或批处理作业)。 ● 调整和验证应用程序参数和命令行标志。 ● 为缺少的API抽象实现解决方案,比如包(映像)管理。 ● 应用程序的配置模板库。 ● 发布管理工具 ● 镜像版本指定 <br />  为了应付这些需求,配置文件管理系统倾向于发明一种特定于域的配置语言,该语言能够成为图灵完整的,从对配置中的数据执行计算开始(调整内存量以根据服务中的分片数量为服务器提供服务),其结果是一种难以理解的“配置就是代码”,人们试图通过消除应用程序源代码中的硬编码参数来避免这种情况。它不会降低操作的复杂性,也不会使配置更容易调试或更改;它只是将计算从一种实际的编程语言转移到一种特定于领域的语言,该语言通常具有较弱的开发工具,例如调试器和单元测试框架。 <br />  我们认为最有效的方法是接受这种需求,接受程序化配置的必然性,然后维护一个清晰的分割在计算与数据之间。这种语言对于呈现数据应该当简单,数据格式仅仅像JSON或者yaml那样。并应以一种真正的编程语言对这些数据进行编程修改,这里有很好理解的语义,以及良好的工具,有趣的是,这种计算和数据的分离也可以在Angular等框架的前端开发中看到,Angular在标记(数据)和JavaScript(计算)之间保持了清晰的分离。 ## <br />**Dependency management(依赖管理)** 运行一项服务通常意味着运行一系列的相关连的服务(例如监视,存储,持续交付与集成),如果一个应用程序对于其他应用程序有所依赖,如果这些依赖可以被集群管理系统自动安装与初始化不是很nice吗(以及它们可能具有的传递依赖关系)? <br />  更为复杂的东西,实例化的依赖关系并不像启动一个新副本那么简单,例如,它需要在已有的服务上注册为一个消费者。(例如Bigtable 作为服务)以及传递认证方式,授权。以及这些传递依赖项中的计费信息。然而,几乎没有系统能够捕获、维护或公开此类依赖信息,因此在基础设施级别实现自动化甚至是常见的情况几乎是不可能的。对于用户来说,打开一个新的应用程序仍然很复杂,对于开发者来说,这使得开发新的服务更为困难。and often results in the most recent best practices not being followed,(并经常导致未遵循最新的最佳做法,)这又会影响到servers的可靠性。 <br />  一个显著的问题是,如果手动提供依赖项信息,则很难使其保持最新状态,and at the same time attempts to determine it automatically (e.g., by tracing accesses) fail to capture the semantic information needed to understand the result.(Did that access have to go to that instance, or would any instance have sufficed?)取得进展的一种可能方法是要求应用程序枚举其依赖的服务,并让基础设施拒绝允许访问任何其他的。(我们这样做是为了在构建系统中进行编译器导入。)例如自动设置、身份验证和连接。不幸的是,表达,分析和使用系统依赖关系的系统的复杂性太高了,因此他们还没有被添加到主流的容器管理系统中,我们仍然希望kubernetes能够成为一个能够构建这类工具的平台,但这仍然是一个挑战。 ## <br />**结语:** 这一个十年来建立容器管理系统的经验教会了我们许多,我们已经把我们学到的许多都放入到了Kubernetes中,我们的目标是建立一个明显能够使得程序的生产效率得以提升并且能够帮助我们自动化的管理的系统,我们希望您能够加入我们去扩展与提升他。