Kubernetes 1.3 的性能和弹性 —— 2000 节点,60,0000 Pod 的集群

我们自豪的宣布 Kubernetes 1.3 的发布,现在能够在支持 2000 节点规模的集群上提供更好的端到端 Pod 启动时间。API 调用的延迟符合我们的一秒钟的 服务水平目标( SLO ),并且多数情况下是远远优于这一目标的。如果不考虑 SLO 限制的话,还可能运行超过 2000 节点的集群。

本文中我们要讨论 Kubernetes 1.3 的性能细节,以及性能增强的原因——我们对 1.2 版本的性能改进。另外还会讲讲 Kubemark,这一工具已经被集成到我们的持续测试框架,用来对性能和弹性进行回归测试。

评估方法

前文中我们说明了我们的测试场景。1.2 之后最大的(测试场景的)变化就是我们创建和试用了多个命名空间。在 2000 节点/ 60,000 Pod 的测试中,我们建立了 8 个命名空间。这样测试的原因是,我们认为使用如此规模集群的用户,极有可能使用多个命名空间。

Kubernetes 1.3 的表现

那么 Kubernetes 1.3 的性能到底怎样?下图展示了 1000 和 2000 节点集群中,Pod 启动的端到端时延。为了跟 1.2 进行比较,我们还加入了 1000 节点规模的 1.2 版本的集群的数据。

pod startup latency

接下来的图表显示了 2000 节点的 1.3 集群中的 API 延迟。

pod startup latency

API call latencies

我们如何做到这一进步?

1.3 中针对弹性的最大变化就是加入了基于 Protocol Buffer 的高效序列化格式,来替换 JSON。这一技术主要用于在 Kubernetes 控制组件之间进行通信,当然所有跟 API 服务器进行的通信都可以使用这一格式。为了兼容考虑,JSON 仍然会被支持。

目前还没有对 ETCD 中存储的数据进行这一改造,这部分的功能还在开发之中。这一功能目前已经接近完成,我们希望能在 1.4 中完成这一存储方式的切换。根据经验来说,这一改变能够缩减 30% 的Pod 启动时间。

我们如何测试 Kubernetes 的弹性?

创建具有 2000 节点的集群是昂贵又耗时的一个操作。但是我们每次发布都需要通过测试来获取真实的性能和弹性相关的数据。我们还需要一个轻量级的机制来快速的评估我们在性能方面的想法,要能够在持续运行框架完成性能的回归测试。为了这一系列的需要,我们开发了称为Kubemark的工具。

Kubemark 是什么?

Kubemark 是一个让用户能够在虚拟集群上进行试验的性能测试工具。我们用它来测量大集群的性能数据。

Kubemark 集群由两个部分组成:一个真正的运行了正常 Master 组件的 Master 节点,以及一系列的 "hollow" 节点(虚节点)。"hollow" 这一前缀的意思是,这些组件的一部分功能是虚拟的。最好的例子就是hollow-kubelet,他看起来是一个普通的 Kubelet,但是他不会启动任何的容器,也不会加载任何的存储卷。他只是“声称”自己完成了任务,所以在 Master 的视角中,他是一个真的 Kubelet。

既然我们要让 Kubemark 集群运行的好像真的一样,我们复用了真正的 Kubelet 代码,其中注入了一个假的 Docker 客户端。类似的情况还有 hollow-proxy(等价于 KubeProxy)使用了真实的 KubeProxy 代码,只是注入了空操作的 Proxier 接口(不操作 iptables)。

下面的变更很有用

  • 因为不会改变运行环境,所以可以在一台机器上运行多个hollow-node
  • 由于没有运行真正的容器(例如 Docker),在一台单核心的机器上,我们最多可以运行 14 个hollow-node
  • hollow-node的生命周期很完整,因此会对 API 服务器造成几乎同样的负载,也就是说他们能够为性能测试提供可靠的压力(其中有一个显著的不同就是这一过程没有模拟任何错误——例如容器错误),未来我们考虑向框架中加入这一部分功能。

我们如何建立 Kubemark 集群?

这里我们用了 Kubernetes 自身的能力——在 Kubernetes 集群上运行 Kubemark 集群。

要创建一个具有 N 个节点的 Kubemark 集群:

  • 创建一个普通的 Kubernetes 集群,在其中运行 N 个hollow-nodes,(也就是说,要创建一个 2000 节点的 Kubemark 集群,我们要使用一个具有 22 个 8 核节点规模的 Kubernetes 集群)。
  • 创建一个独立的虚拟机,用来运行 Kubemark 集群的所有 Master 组件( etcd, api server, controllers 以及 scheduler 等)。
  • 在 Kubernetes 集群上编排 N 个hollow-node的 Pod。这些hollow-node会跟上面提到的独立虚拟机上的 Master 组件进行通信。
  • 最后,我们创建一些附加 Pod(目前只有 Heapster)到 Kubernetes 集群上,并配置他们同 Kubemark API 服务器通信。

这些步骤完成之后,我们就有了一个可用的 Kubemark 集群,可以用来运行(性能)测试了。我们开发了用于 GCE 环境的脚本来做这些事情,并编写了指南来提供更多相关内容。

值得一提的是,在我们测试 Kubemark 的时候,同时也是对下面的 Kubernetes 集群进行了测试——显而易见的,如果底层集群无法正常工作,测试是无法进行的。

Kubemark 和真实集群的性能测量结果差异

至关重要的一点,Kubemark 集群的性能跟真实集群是很相近的。对于 Pod 的端到端启动延迟来说,下图证明了其中微乎其微的差异:

Real cluster vs Kubemark

API 相应测试结果来看,差异就大了一些,一般不会超过两倍。然而趋势还是一致的:真实集群的改善和衰减,都会以相似的比例反映在 Kubemark 的结果中。

Real cluster vs Kubemark

结论

我们在 Kubernetes 的性能和弹性上做出了持之不懈的努力。在本文中我们展示了 1.3 版本中,在符合 SLO 要求的情况下,扩大集群规模到 2000 节点,这是我们 1.2 以来大量改进的结果。我们也讲述了 Kubemark 这一模拟框架,让我们能够快速评估代码变更带来的性能变化,不论是对于性能方面的点子,还是持续测试框架中,都起到了举足轻重的作用。