写点什么

Docker 背后的容器集群管理——从 Borg 到 Kubernetes(二)

  • 2015-07-28
  • 本文字数:9263 字

    阅读完需:约 30 分钟

在本系列的第一部分《 Docker 背后的容器集群管理——从 Borg 到 Kubernetes(一)》中,我们对 Borg 系统进行了深入的剖析,并且同它的衍生项目 Kubernetes 进行了逐一地比较。这一部分对比包括了 Borg 和 Kubernetes 的各类核心概念、任务类型划分、资源管理和分配方式、配额和优先级机制,以及最关键的调度策略。这些分析涵盖了原论文前四章的主要内容。

从这些比较中我们不难发现,虽然 Kubernetes 与 Borg 有很多相似的地方,但是在很多关键特性上 Kubernetes 明显进行了重新设计。而 Borg 的作者之所以要这么做,最主要的原因是除了任务容器的编排调度和管理之外,Borg 需要比 Kubernetes 更加关注这样一个事情:如何最大程度地提高集群的资源利用率?

注:本文作者张磊将在 8 月 28 日~29 日的 CNUT 全球容器技术峰会上分享题为《从0 到1:Kubernetes 实战》的演讲,演讲中他将重点剖析Kubernetes 的核心原理和实践经验,并分享大规模容器集群管理所面临的问题和解决思路。

1. 利用率

所以,本节讨论的集群利用率优化可以说是 Borg 的精华所在,也是 Borg 系统与其他类似项目相比最大的亮点之一。那么 Borg 的具体做法是怎样的呢?

如果用一句话来解释,Borg 做了最主要工作就是来回收再利用任务的空闲资源,并且对不同的回收策略做出了科学的评估。

所以我们接下来先从这个评估方法入手。

1.1 利用率的评估方法

前面已经提到过,Borg 中进行任务的调度既需要考虑机器的资源可用性(包括抢占),也要考虑任务本身的约束要求(比如"我需要 SSD 机器"),还需要考虑应对压力峰值所必需的空余量。而在本节,我们还要为调度再加上一条规则,那就是对于 batch job 来说,它们还需要能够利用从 LRS 任务上回收来的资源。这种情况下,调度过程中的资源抢占和回收机制带来了一个负面影响:Borg 很难快速而精确地回答"某个机器 / 集群到底还有多少资源可用"这样的问题。

可是,为了能够评价不同的调度算法,Borg 必须能够评估集群的资源使用情况。很多情况下,运维人员会计算一个一段时间内的集群"平均利用率"来作为评价指标,但是 Borg 则使用了一个叫 “压缩实验” 的方法。所谓压缩实验,即不断减少工作单元(Cell)中机器的数量(“压缩”),然后重调度某个指定的任务,直到该任务再也不能正常调度运行在这个集群上。这个过程不断进行的最终结果,得到就是这个任务运行所需的"最小工作单元"的定义。

这个指标清楚地表明了当资源减少到什么程度时,我们才可以终止这个任务,并且这个生成指标的过程不需要提交任何『模拟』任务,这样得到的结果要精确很多。

当然,上述『压缩』的过程自然不能在生产环境中开展。这时我们前面提到的模拟器:Fauxmaster 的作用就发挥出来了。Borg 可以加载某时刻的 checkpoints,从而在 Fauxmaster 上重现出与当时一模一样的环境(除了 Borglet 是模拟的之外)。

在具体进行压缩的过程中,Borg 还使用了以下几个小技巧:

  • 随机选择机器来移除。
  • 对每一个任务进行上述压缩实验(除了某些跟机器紧密绑定的存储型任务)。
  • 当 Cell 的大小减小到一定程度时(比如剩余资源只有 Job 所需资源的二倍),将硬性约束改为非硬性约束,从而适当增加调度成功的几率。
  • 允许最多 0.2% 的”挑剔型“任务挂起,因为它们每次都会被调度到一小撮机器上。
  • 如果某次压缩实验需要更大的 Cell,管理员可以将原 Cell 克隆几份再开始“压缩”的过程。
  • 上述压缩实验会在每一个 Cell 中重复 11 次,每一次都会选择一个不同的随机数种子来移除机器。

所以,通过上述压缩实验,Borg 提供了一种直观的、可以用来评估不同调度策略优劣的测试方法。即: 调度策略越优秀,对于同一个任务来说它最后得到的最小工作单元中所需的机器数就越少

不难发现,Borg 对资源使用进行评估的方法关注的是一个任务在某一具体时刻运行起来所需的最少的资源成本,而不是像传统做法那样去模拟并重现一个调度算法的执行过程,然后跟踪检查一段时间内集群负载等资源指标的变化情况。

当然,在生产环境中,Borg 并不会真的把资源『压缩』到这么紧,而是给应对各类突发事件留有足够余量的。

1.2 Cell 的共享

Borg 进行高效的集群管理最直接的一个优化方法就是任务的混部。这里 Borg 进行了一项对比实验,即把 LRS 和 batch job 分别部署到不同的集群中,结果同样的硬件和任务条件下我们需要比 Borg 多 20%-30% 的机器。造成这种情况的关键原因是:prod 级别的任务(即大多数的 LRS)实际使用的资源比它申请的资源要少很多,而 Borg 会回收这部分资源来运行 non-prod 级别的任务(比如大多数 batch job)。

另一方面,不仅是不同类型的任务在 Borg 中混合部署,不同用户的任务也是混合部署的。Borg 的实验表明,如果在一定条件下(比如此 Cell 上任务所属的不同用户数量达到一定值)自动将不同用户的任务隔离到不同 Cell 上,那么 Borg 将需要比现在多 20-150% 的机器才能满足正常的运行要求。

看到这里,相信很多读者也会产生同我一样的疑问:把不同类型、不同用户的任务混合在一台机器上运行,会不会造成 CPU 时间片的频繁切换而降低系统性能呢?为了回答这个问题,Borg 专门以 CPI(cycles per instruction,每条指令所需的时钟周期)的变化为指标对任务与 CPI 之间的关系做出了评估。

这里 Borg 使用的评估方法是:将 Cell 分为『共享的 Cell』(混部)和『独享的 Cell』(不混部),然后从所有 Cell 中随机选择 12000 个 prod 级别的任务,然后再这些任务中进行为期一周的持续采样。每次采样间隔 5 分钟,每次采样都统计被选中任务的 CPU 时钟周期和指令数目。这个过程最后得出的结论包括:

一、CPI 数值的变化与两个变量的变化正相关:机器本身的 CPU 使用量,机器上的任务数量。任务数量对 CPI 的影响更大:在一台机器上每增加一个任务,就会将这台机器上其他任务的 CPI 增加 0.3%;而机器 CPU 使用量每增加 1%,指令 CPI 的增长只有 0.2% 左右。但是,尽管存在上述关系,实际生产环境中 Borg 只有很小一部分 CPI 变化是由于上述两个变量的改变造成的,更多 CPI 变化的诱因是应用本身实现上(比如算法,数据库连接等)对 CPU 的影响。

二、共享的 Cell 与独享的 Cell 相比,有大约 3% 的 CPU 性能损失。这个结论是通过比较这两类 Cell 上的采样结果得到的,也表明了混部策略确实会一定程度上降低 CPU 的表现。

三、为了避免(二)中的结论受到应用本身差异行的干扰(比如被采样任务本身就是 CPU 敏感的),Borg 专门对 Borglet 进程做了 CPI 采样:因为这个进程在整个集群中完全同质,并且同时分布在独享 Cell 和共享 Cell 的所有机器上。这时,测试得出的结论是独享 Cell 上的 Borglet 进程的 CPU 表现要比共享 Cell 上好 1.19 倍。

综上,通过上述系统地测试,Borg 确认了 共享 Cell 会给任务带来 CPU 上的性能损失 ,但是相比任务混部所带来的机器数量的大幅节省,上述 CPU 损失还是很可以接受的。更何况,机器数量减少不仅仅节省了 CPU,还节省了大量内存和磁盘的成本,与这些相比,任务混部在 CPU 上造成的一点浪费确实微不足道。

1.3 使用更大的 Cell

Borg 还做了一个很有意义的测试,那就是将一个大 Cell 中的任务分开部署到跟多小 Cell 中(这些任务是随机挑选出来的)。结果表明,为了运行这些任务,小 Cell 需要比大 Cell 多得多的机器才能正常工作。

1.4 细粒度的资源请求

Borg 用户提交的任务使用一个 CPU 核心的千分之一作为单位来申请 CPU,使用字节为单位来申请内存和磁盘,这与 Kubernetes 里的资源单位是一样的。这种情况下,一个常见的资源请求描述如下所示:

复制代码
"cpu": 1000,
"memory": 1048576,

请求中具体需要某种资源量的大小完全由用户决定,并且一旦该任务创建成功,上述参数会作为任务进程的 cgroup 参数来限制任务的资源使用情况。

不难发现,Borg 以及 Kubernetes 的资源请求粒度都是小而灵活的,这也是基于容器的编排管理平台的一大特点:资源粒度直接对应到 cgroups 的配置上,所以用户可以进行非常精细的调节。在这种情况下,提供类似于『1 个 CPU,1G 内存』这种固定的资源配额 offier 来供用户选择的做法就不够明智了。

事实上,这种细粒度的资源请求一方面能够减少资源请求的聚集(比如可能 90% 的任务都要求『个 CPU,1G 内存』)所造成资源碎片化,另一方面还能有效地避免本来无关的两种资源发生不必要的关联(比如为了申请 1 个 CPU,任务必须申请 1G 内存)。在试验中,Borg 直接展示了如果用户使用资源配额 offer 来持续向 Borg 请求资源(比如 OpenStack 就只为用户提供了的 tiny、medium、large 等几种可选的 offer),Borg 所管理的集群将需要比原先多 30%-50% 的机器才能支撑同样规模的任务运行。

1.5 资源回收

终于来到了关键的部分。我们前面已经不止一次提到过,Borg 通过任务混部提高集群利用率的一个重要基础就是资源的回收和重分配。

准确来讲,资源回收主要发生在任务调度的资源可行性检查阶段。举个例子,假设一台机器的容量是 10G 内存,并且已经有一个申请了 4G 内存的任务 A 在运行,那么这台机器的剩余可用资源就是 6G,另一个申请 8G 内存的任务 B 是通不过可行性检查的。但实际情况是,Borg 会在一段时间后把任务 A 申请的内存改成 1G,使得调度器认为这台机器的剩余可用资源变成 9G。这样,任务 B 就可以调度成功并且运行在这台机器上了,这就是说任务 B 使用了回收自任务 A 的一部分资源。这个过程具体实现是怎样的呢?

在 Borg 中,任务申请的资源 limit 是一个上限。这个上限是 Borg 用来确定一台机器的资源是否足够运行一个新任务的主要标准。

既然是上限,大多数用户在设置这个 limit 时都会故意把这个值设置的稍微高一点,以备不时之需。不过,大多数时候任务的资源使用率都是比较低的。为了解决这个问题,Borg 做了一个非常有意义的工作,那就是先为每个任务估算它真正需要使用的资源量,然后把空闲部分资源回收给那些对资源要求不是很高的任务来使用。这部分回收资源的典型使用者就是非生产环境任务,比如 batch job。

这个估算过程由 Borgmaster 通过 Borglet 汇报的资源使用情况每隔几秒计算一次,得出的资源使用量称为 “资源预留” 。一个任务的资源预留在最开始是与用户设置的 limit 相等的(即等于任务请求的资源量),在任务成功启动一段时间后(300s),它的资源预留会 慢慢减少 为任务的 实际资源使用量加上一个可配置的安全余量 。另一方面,一旦任务的资源使用量突然增加并超过了上述资源预留,Borg 会 迅速 增加它的资源预留到初始值来保证任务能够正常工作。

需要注意的是,生产级别的任务(prod 级别的任务)是永远不会使用回收而来的资源的。只有对于非 prod 级别的任务来说,它们在被调度的时候 Borg 才会把可回收资源纳入到可行性检查的范围内,正如我们前面介绍的那样。

既然是估算,Borg 就有可能会把过多的任务调度在一台机器上从而造成机器的资源被完全耗尽。更糟糕的是对于任务来说,它们的实际资源使用量却完全是处于各自 limit 范围内的。在这种情况下,Borg 会杀死一些非 prod 级别的任务来释放资源。

Borg 内部的实验表明如果在当前集群中禁用资源回收的话,将近一半的 Cell 都需要额外增加 30% 的机器才能支撑同样规模的任务。而在 G 的生产环境中,则有近 20% 的任务是运行在这些回收来的资源上的。并且 Borg 对内部任务的统计再次验证了:对于绝大部分任务而言,它的实际的资源使用相比它申请的资源限制来说都是很低的,将近一半机器的 CPU 和内存使用量不到 20%。

最后的问题是,我们应该为给任务设置多大的安全余量呢?不难想到,如果安全余量设置得很小,我们就可以实现更高的资源利用率,但是也更容易出现使用量超出资源预留的情况(此时就会 OOM)。相反,如果把安全余量设置得很大,那资源利用率就不可能很高,当然 OOM 的情况也会减少。这里 Borg 给出的答案是通过实验来得出合理的值:给定不同的安全余量值,分别观察不同余量下资源利用率和 OOM 在一段时间内的的变化,然后选择一个资源利用率和 OOM 出现次数的平衡点来作为整个集群的安全余量。

2 隔离与性能

前面说了那么多共享的内容,读者应该可以猜到 Borg 的机器上运行着的任务密度应该是很高的。事实的确如此:一半以上的 Borg 机器上同时运行着 9 个以上的任务,这其中绝大多数机器运行着约 25 个任务、开启了 4500 个线程。共享给 Borg 带来了极高的资源利用率,但是也使得这些任务间的隔离成为了一个不得不重点解决的问题。

2.1 任务间隔离

Borg 最早是直接使用 chroot 和 cgroup 来提供任务间的隔离和约束,并且允许用户通过 ssh 登陆到这些隔离环境中来进行调试。后期这个 ssh 登陆的办法被替换成了 borgssh 指令,即通过 Borglet 来负责维护一个用户到隔离环境内 shell 的 ssh 连接。需要注意的是,来自外部用户的应用是运行在 GAE 或者 GCE 上的,而不是直接作为 Borg 任务来跑的。其中 GAE 作为 PaaS 主要使用的是砂箱技术来支撑和隔离用户的应用,而 GCE 作为 IaaS 自然使用的是 VM 技术。值得一提的是无论 GAE 还是 GCE,它们所需的 KVM 进程则是作为 job 运行在 Borg 上的。

Borg 的早期阶段对于资源限制做的还是比较原始的,它只在任务调度成功后对内存、磁盘和 CPU 的使用情况进行持续的检查,然后依据检查结果杀死那些使用了太多资源的任务。在这种策略下,Borg 任务间的资源竞争是很普遍的,以至于有些用户故意将任务的资源请求设置的很大,以期尽量减少机器上同时运行的任务数,这当然大大降低了资源利用率。

所以,很快 Borg 就开始使用 Linux 容器技术来解决限制与隔离的问题。G 家内部的容器技术有一个对应的开源项目,这就是曾经名噪一时的 lmctfy 容器( https://github.com/google/lmctfy )。确切地说,lmctfy 给用户提供了一个可以方便地配置 cgroup 的工具,并能够把用户的这些 cgroup 配置结合 namespace 创建出一个任务隔离环境即『容器』出来。由于 lmctfy 从一开始就是从限制与隔离的角度来开发的,所以它的资源操作接口定义地很丰富,不仅涵盖了 cgroup 的大部分子系统,还可以进行嵌套等比较复杂的资源管理。但是,随着 Docker 容器镜像这一杀手级特性的普及以及 Docker 本身飞快的演化,lmctfy 的作者们也不得不放弃了该项目的维护,转而开始去贡献 libcotainer 项目。不过至于现在 G 家内部,应该还是在使用类似于 lmcty 这种自研的容器技术栈,而 Docker 则主要用作对外提供的公有云服务(Google Container Engine)。

当然,容器也不是万能的,一些底层的资源共享问题比如内存带宽的共享或者 CPU 缓存污染问题在 Borg 中仍然存在,但是至少在任务的运行资源的限制和调度优化上,上述容器技术已经足够了。

2.2 性能优化

我们前面提到过,Borg 中的任务是分为 LRS(也可以称为 Latency Sensitive 任务)和 batch job 的,其中前者因为对于访问延时敏感所以可以享受更好的『待遇』,这个划分是 Borg 进行资源回收和在分配的基础。但是还有个待解决的问题是,哪种资源是可以在不影响任务运行的前提下进行回收的呢?

凡是能够进行热回收的资源在 Borg 中都称为可压缩资源,典型的例子是 CPU 周期和磁盘 I/O 带宽。与之相反,内存和磁盘空间这种就属于不可压缩资源。当一台机器上不可压缩资源不够用时,Borglet 就不得不按照优先级从低到高杀死任务,直到剩余任务的资源预留能够得到满足。而如果是可压缩资源不足,Borg 就能够从某些任务上面回收一些资源(一般从 LRS 任务上,因为它们申请的资源一般都比实际使用多一些)而不需要杀死任何任务。如果回收资源仍然解决不了问题,那么 Borg 才会通过 Borgmaster 将一些任务从这个机器上调度走。

具体到 Borglet 的实现上同样体现了对资源的限制和管理。Borglet 维护了一个内存资源检测循环,它负责在调度时按照资源使用预测的结果(对于 prod 级别任务),或者按照当前内存使用情况(对于非 prod 级别任务)为容器设置内存限额。同时,这个循环还负责检测 OOM 事件,一旦发现有任务试图使用比限额更多的内存时 Borglet 将杀死它们。而前面刚刚提到的不可压缩资源(内存)不足时的处理也是这个循环完成的、

为了让 LRS 任务获得更好的性能,LRS 可以完全预留某些或者所有 CPU 核心,并且不允许其他的 LRS 任务运行在这些 CPU 核心上。另一方面,batch job 则不受此限制,它们可以随时运行在任意 CPU 核心上,但是在 CPU 调度上 batch job 会被分配更小的配额,即它们能占有 CPU 的时间要比 LRS 少。

不难看出,为了能够更加高效的使用 CPU 资源,Borg 就必须引入更加复杂的任务调度策略,这也就意味着调度过程会占用更多的时间。所以,Borg 的开发者对 CPU 调度做了优化以期在最小的时间代价里完成调度过程。这些优化包括在内核 3.8 引入的以进程或者进程组为单位的新的 CPU 负载计算方法(per-entity load tracking),在调度算法中允许 LRS 抢占 batch job 的资源,以及减少多个 LRS 共享同一 CPU 时的算法的执行次数。

上述优化的结果使得绝大多数任务都能够在 5ms 内获得 CPU 时间片,这比默认的 CFS 高效很多。不过在一些极端情况下(比如任务对调度时延非常敏感时),Borg 会使用 cpuset 来直接为任务分配独享的 CPU 核心。不过,这种需要设置 cpuset 的情况非常少见,而且 Borg 的作者不止一次告诫容器的使用者不要同时设置 cpu.shares 和 cpuset:因为这会给后续系统的 CPU 超卖,auto-scaling,统一资源单位的抽象等设计带来很多麻烦。这其实很容易理解:cpu.shares 是一个相对值,随着任务(容器)的增加每个容器真正享有的时间片数量是会不断变化的,而在一个任务必须和某个 CPU 绑定的前提下,每个任务到底能分配到多少时间片这种问题就要变得复杂很多。这也是为什么 Kubernetes 暂不支持用户设置 cpuset 的一个主要原因。

虽然 Borg 任务能够使用的资源取决于它们的 limit,其实大多数任务的可压缩资源比如 CPU 是可以超卖的,即它们可以使用超出限额的可压缩资源(比如 CPU)从而更好地利用机器的空闲 CPU。只有 5% 的 LRS 和不到 1% 的 batch Job 会禁止超卖以期获得更精确的资源使用预测。

与 CPU 相反,Borg 中内存的超卖默认是禁止的,因为这会大大提高任务被杀死的几率。但即使如此。仍然有 10% 的 LRS 和 79% 的 batch job 会开启内存超卖,并且内存超卖对于 MapReduce 任务来说默认就是开启的。这也正对应了 1.5 中 Borg 关于资源回收的设计:batch job 更倾向于使用回收来的资源并且驱使系统进行资源回收。

大多数情况下以上策略都能够有助于资源利用率的提高,但是这也使得 batch job 不得不在某些情况下牺牲自己来给迫切需要运行资源的 LRS 任务让路:毕竟 batch job 使用的资源大多是从别人那里回收来的。

与 Borg 相比,Kubernetes 的资源模型还在开发的过程中,当前能够支持的类型也只有 CPU 和内存两种,其他类似于磁盘空间、IOPS、存储时间和网络带宽等都还处于概念设计阶段。出于跨平台的考虑,Kubernetes 的 CPU 资源的度量会被换算成一个内部统一的 KCU 单位,比如 x86 上 KCU 就等于 CPU 时间(类似 Borg)。同 Borg 一样,Kubernetes 中的 CPU 也是可压缩资源,而内存就是不可压缩资源了:虽然我们随时可以通过 cgroup 增加 Docker 容器的内存限制,但是只有这些 page 被释放之后进程才可以使用它们,否则仍然会发生 OOM。

总结

Borg 目前披露的细节就是这么多了,从这些内容上,我们不难看出作为 Google 超大规模任务容器集群的支撑平台,Borg 对于资源混部与集群利用率的优化工作可以说是整篇文章的精髓所在。另外,尽管作者在最后声称后续工作主要是 Kubernetes 的研发和升级,但是我们绝不能说 Kubernetes 就是开源版的 Borg。

尽管很多概念包括架构、甚至一些实现方法都借鉴了 Borg,开发者也基本上是同一拨人,但是 Kubernetes 与 Borg 关注的问题存在着根本的差异。

Kubernetes 的核心是 Pod,然后围绕 Pod,Kubernetes 扮演了一个 Pod 集群编排的角色,在此基础上它又为这些 Pod 集群提供了副本管理(ReplicationController)和访问代理(Service)的能力。所以,Kubernetes 实际上更贴近 Swarm 这样的 Docker 容器集群管理工具,只不过它的管理单位是 Pod。这样的定位与 Borg 专注于支撑内部任务并且最大程度地提高资源利用率的初衷是不一样的。很难想像会有人把 KVM 或者 MapReduce Job 跑在 Kubernetes 上,而这些却是 Borg 的典型任务。

相比之下,Mesos 关注的核心问题是集群环境下任务资源的分配和调度,这与 Borg 的一部分目标很接近。但是,两层调度策略决定了 Mesos 本身的实现是十分轻量的,它的大部分工作在于如何在兼顾公平和效率的情况下向上层框架提供合理的资源邀约,至于对运行其上的任务本身 Mesos 的关注并不算多(交给上层 framework 负责即可)。

那么有没有一个开源项目能够配上开源版 Borg 的称号呢?目前看来是:Aurora+Mesos。

Apache Aurora 项目在 Mesos 的基础上提供了很多非常有意思的特性,这其中就包括了同时运行 batch job 和普通应用,任务优先级和资源抢占的能力。当然,从时间点上来看很可能是 Aurora 借鉴了 Borg 的思想,但最关键的是,Aurora 把集群利用率的提高当作了该项目的主要目标之一,这才使得它与 Borg 产生了更多的交集。

当然,至于选择哪种,就完全是取决于用户的需求了。从各个项目的发展上来看,集群规模不大又需要 Pod 概念的话,直接使用 Kubernetes 就足够了,但如果是互联网企业部署自己内部的私有云的话,还是建议先搭一层 Mesos 作为集群资源的抽象(已经有自己的资源编排平台的同学除外,比如百度 Matrix 这类),然后使用不同的 framework(包括 Aurora,Marathon 以及 Kubernetes 本身)来满足不同场景的需求。

最后说一句,作为 Borg 的同源衍生项目,Kubernetes 的 Roadmap 里还有很多 Borg 的优秀特性待实现,比如我们前面提到过的资源模型,对 batch job 的支持等都是很好的例子。可以预见,Kubernetes 接下来很有可能会发展成为一个『大量借鉴 Borg 优秀思想、架构、以及代码实现』的一个加强版 Swarm,这本身确实很让人期待,这也是目前 Kubernetes 在用户眼中可能要比 Mesos 稍胜一筹的原因之一。更何况,Google 已经与 Mesos 达成了战略合作,Kubernetes 和 Mesos 今后的分工会更加明确,重叠功能会更少。这也意味着在核心功能足够完善前,Kubernetes 对资源利用率提升等问题上的重视程度依然不会非常高。

无论如何,当 Docker 遇上 Borg,这绝对是一件非常有意义的事情。在后续的文章里,我们会进一步对以 Docker 为核心的容器集群的编排管理、调度、监控和性能优化进行更多的深入的剖析和解读。

作者简介

张磊,浙江大学博士,科研人员, VLIS lab 云计算团队技术负责人、策划人。

参考文献

  1. http://research.google.com/pubs/pub43438.html
  2. https://github.com/googlecloudplatform/kubernetes

感谢郭蕾对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ @丁晓昀),微信(微信号: InfoQChina )关注我们,并与我们的编辑和其他读者朋友交流(欢迎加入 InfoQ 读者交流群)。

2015-07-28 00:086707
用户头像

发布了 40 篇内容, 共 24.8 次阅读, 收获喜欢 141 次。

关注

评论

发布
暂无评论
发现更多内容

软件测试/测试开发丨MockServer 服务框架设计

测试人

软件测试 自动化测试 测试开发

Go error 源码解读、错误处理的优化与最佳实践

烤冷面

golang golang 面试

架构实战营 - 模块五作业(微博评论)

🐢先生

架构实战营

系统设计的端到端原则

俞凡

架构

常用对话框基本使用

向阳逐梦

dialog timepicker progress

作为移动开发你不能不了解的编译流程

京东科技开发者

编译器 移动开发 京东云 京东技术

交易履约之产品中心实践

京东科技开发者

交易 京东云 京东技术 京东科技 产品中心

软件测试/测试开发丨持续交付-Jenkinsfile 语法

测试人

软件测试 自动化测试 测试开发

中台的悖论

agnostic

中台

CMS系统是什么?

源字节1号

开源 软件开发 前端开发 后端开发 小程序开发

人工智能与软件工程

紫晖

人工智能 机器学习 软件工程 工程

运维训练营第19周作业

好吃不贵

在京东如何做好前端系统的可观测性

京东科技开发者

前端 京东云 京东技术

软件测试/测试开发丨持续交付-Pipeline入门

测试人

软件测试 自动化测试 测试开发

手把手带你上手ChatGPT

老周聊架构

3月月更 ChatGPT

利用 ChangeStream 实现 Amazon DocumentDB 表级别容灾复制

亚马逊云科技 (Amazon Web Services)

如何实现云数据治理中的数据安全?

京东科技开发者

数据库 云计算 京东云 京东技术

基于 Kafka 和 Elasticsearch 构建实时站内搜索功能的实践

京东科技开发者

MySQL ES 京东云 京东物流 京东技术

AR市场为何频频“呼唤”苹果?

Alter

AR

什么是容器编排及编排的优点

黎博

容器编排 Kubernetes Serverless

实现常驻任务除了避免昙花线程,还需要避免重返线程池

newbe36524

C#

Docker背后的容器集群管理——从Borg到Kubernetes(二)_Google_张磊_InfoQ精选文章