治大国若烹小鲜,大规模Kubernetes集群的运营哲学
鲍永成 TIGCHAT 昨天
有些人会说,Kubernetes 已经这么成熟了,都是开源的,而且已经有这么多的工具进行部署监控了,集群的运维会有什么难度。其实不然,集群运营,特别是大规模集群运营,需要丰富的经验,成熟的体系,辅助的工具链等等,因此其难度并不亚于开发一套大型系统。所谓治大国若烹小鲜,集群需要精细化的运营,对于细节的要求更是严格甚至苛刻。
因为你直面的是生产环境,作为基础设施和平台,小小的疏漏可能会酿成规模性的灾难后果,这也是被无数案例实证过的教训。所以,在上生产环境前,我们的建议是要问一下自己:大规模集群,你准备好了么?如何准备,相信很多人会一下子感觉无处着手,没有头绪。这里,我们把我们的一些经验分享给大家。
稳定三问
稳定性是基础设施的生命线。所谓皮之不存,毛将焉附。如果系统不稳定,那么其他的再多花哨的功能也没有存在的必要和基础。从 OpenStack 到 Kubernetes,我们团队积累了丰富的运营经验,特别对于稳定性的需求,深有体会。我们将关于稳定,总结为了稳定三问。在集群运营之前,就要先对照这三个问题,来对照下自己的集群是否足够稳固。
三问之一:任意组件挂掉 / 拥塞,会影响已运行的容器么?
从 OpenStack 到 Kubernetes,集群管理都是有若干独立项目和若干个组件组成的。这些组件相互合作,构建成了整个容器的生态。这其中,有集群管理的组件,有网络管理的组件,有存储管理的组件,有镜像管理的组件,凡此种种,都属于本文中的组件范畴。
第一问,这任意组件挂掉 / 拥塞,会影响已运行的容器么。这个在 OpenStack 中容易回答一些,因为相对来说,OpenStack 对于容器的使用是静态的,因此组件的故障对于已经运行的容器来说,影响会比较小。而 Kubernetes 的运营难度较之 OpenStack 大大提升,其中一个很重要的原因就是 controller 的存在。在实现了较高的自动化的同时,也带来了许多潜在的风险。举例来说,由于某种原因,导致 apiserver 多个节点故障,仅一台 apiserver 进行工作,此时大量的请求 (来自于 kubelet、scheduler、controller 及外部的 api 请求) 均涌入 apiserver,导致 apiserver 很快到达负载上限,大量返回 409 错误。
此时可能若干节点的 kubelet 均无法正常上报心跳,在 controller 处会将其置为 not ready。而后可能会导致由 rs 触发重启的重建,service 摘除相对应节点上容器的流量等等。而实际上,这些节点的容器其实原本是正常运行的。出现问题的,仅仅是 apiserver 的拥塞而已。又比如,采用的网络方案,如果网络元数据的存储故障了,是否会导致现有容器的网络受到影响,是否会导致网络瘫痪。
展开来说,任意组件的挂掉 / 拥塞是否会导致正常容器的重建 / 网络不通等问题,挂掉 / 拥塞是否会导致自动化的误判或者集群的雪崩,所有的组件是否都得到了严格的测试。这些问题均需要认真的审视,对各个组件的工作原理和流程进行详细的梳理,以确保各个环节都在掌握之中。
三问之二:任意组件损坏,集群都能恢复么?
组件的故障,无论是由于组件本身亦或是组件所在的节点故障,在大规模的加持下,发生的概率会大大提高。因此对于各个组件做高可用,设计灾备方式都是十分必要的。不仅如此,对于各组件,特别是关键组件要进行故障的预案设计,并进行恢复演练。正所谓养兵千日,用兵一时。到真正出现故障时,不至于手忙脚乱,毫无头绪。
这里以 etcd 为例。毫无疑问,etcd 是 Kubernetes 的核心中枢。但是 etcd 并不是想象中那么万无一失。在实际生产实践中,遇到过多次莫名其妙的故障,导致整个 etcd 集群无法写入数据,甚至完全故障。最后不得不启动先前的故障预案。在之前的故障预案中,我们做了多种计划和多次演练,包括上策:从 etcd 集群原节点恢复,中策:将数据迁移到新的节点进行恢复,以及下策:从定时备份的数据中恢复。如果从定时备份的数据中恢复,则难免会有一部分数据丢失。在实际中,我们遇到过的最坏情况是将数据迁移到新节点进行集群重建恢复。但是三种情况的演练仍然是必要的,以确保在最坏情况下,仍然能最大限度的保障集群的稳定和安全。
三问之三:任意组件异常,都有告警和相应的处理方式么?
组件的故障异常既然不可避免,那么如何对组件进行监控告警,如何定义告警的规则和和方式,以及告警后如何接入自动化的处理,就需要进行认真的思考。比如,各个组件所在的容器 / 物理机需要配合相应的资源监控告警,组件本身也需要进行健康检查等方式的监控告警,甚而,还需要对组件本身的性能数据进行监控告警。从宏观角度来说,各个组件其实也是一种应用,是平台层或者系统层的应用。所以对于传统的业务应用的一些监控告警手段,一样也可以用于这些组件之上。
<![endif]-->
运营数据与可视化
集群的运营不能靠运维人员的感觉,而是要依赖数据支持。集群运营的数据采集自集群的各个组件,用以反映各个组件的状态、性能等指标,为集群规模的估计提供参考。
运营数据的采集方式多种多样,可以来自于组件的上报,暴露对应的数据接口,通过日志进行数据分析等等。以 apiserver 为例,apiserver 的主要相关数据包括每秒 api 请求的数量、请求时间的统计等。在我们的实际运营中,则更加精细化,通过对于 apiserver 日志的分析,进而统计出每个请求的请求方法、请求的资源类型、namespace、资源名称、请求时间、来源 ip 等等信息,使用 TSDB,在多个维度上进行聚合分析。
以某个测试集群为例,如集群大概 1000 台 node 的规模,pod 数约为 25,000 个,而配合的 configmap 数达到了 15,000。在未进行优化前,api 的 QPS 可以达到 8500 。
我们通过对于请求资源类型的分析,发现 API 各请求资源类型中 configmap 占比可以到 90% 以上。通过进一步分析后,对 configmap 进行了改造,使之支持动态和静态挂载两种方式,将 API 的请求数缩减了 98%,优化后该集群 api 请求仅为 140 。
集群规模不断扩大,因此对于集群的状态需要进行宏观的表达。一种简介明了的方式就是将运营的数据进行收集整理,并使之可视化。实际的运营人员与 Kubernetes 的研发人员对于 Kubernetes 的掌控能力上,还是会有一定的区别。因此可视化可以极大地方便运维人员更好的掌握集群的状态,通过图表对集群的状态和性能有更加直观的感受和体验。同时,可视化也可以清晰看到数据变化的趋势,并结合数据分析集群目前可能存在的问题和遇到的瓶颈,以及对比优化前后的对比,对 Kubernetes 的研发人员也有着极大的参考价值。
借助于运营数据的收集和可视化,我们发现了更多在集群规模扩充时可能发生瓶颈的潜在问题,也对其进行了优化处理。
- etcd 的容量。etcd 默认是 2G 的容量,在大规模的集群下很容易达到瓶颈。因此可以根据不同的 resource 进行分开不同的 etcd 集群进行存储,同时修改 etcd 默认的容量上限。
- etcd 读速率。统计发现,API 中大部分为 GET 请求,因此采用 redis 缓存数据,用以疏解 GET 请求。
- 调度耗时。随着节点数的增加,调度的 predict、priority 流程耗时也随之呈现线性增长。我们删减了不必要的 predict 和 priority 函数,支持采用自适应步长的方式,在小幅牺牲调度准确性的基础上,大幅度提升了调度的速率和吞吐量。
- 镜像中心存储规模与镜像拉取速度。镜像中心我们使用了自研的 ContainerFS 进行存储,并在各个数据中心提供了缓存和 P2P 加速,保证了镜像中心的可扩展性。
运营工具
大规模的运营需要成套的运营工具链进行辅助,缓解运营人员的工作压力,同时也提供更为自动化的流程,对整个集群提供更为稳固的保障。
巡检工具
日常巡检系统对于及时发现物理机及各个服务的异常配置和状态非常重要,尤其是大促期间,系统的角落有些许异常可能就带来及其恶劣的影响,因此特殊时期我们还会加大巡检的频率。 巡检的系统的巡检模块都是可插拔的,巡检点可以根据需求灵活配置。我们将巡检系统用在了各个组件上,用以检查配置、状态、参数等等。
结果样例:
该 plugin 我们已经贡献给社区,并合入了 ansible。
其他工具
除此之外,我们还开发了其他许多工具,这里作一下简要介绍,就不一一详述了:
- kubesql:可以将 Kubernetes 的如 Pod、Service、Node 等资源,处理成类似于关系数据库中的表。这样就可以使用 SQL 语句对于相关资源进行查询。比如可以使用 select count(metadata.name) from kubepod where metadata.namespace = 'default'来查询 ns 为 default 的容器个数。
- event 事件通知:监听 event,并根据 event 事件进行分级,对于紧急事件接入告警处理,可以通过邮件或者短信通知到相关运维人员
- pod/node 全纪录:监听记录 pod/node 的有效状态变化,并记录入数据库中。可以方便查询 pod/node 的变化历史。
在运营了大规模 Kubernetes 集群之后,我们对更高的技术层次发起了挑战,那就是调度。下一章预告《第三章:庖丁解牛,调度的框架与策略》。