作者 | 谢瑶瑶(初扬)
来源|阿里巴巴云原生公众号
随着容器技术的不断发展迭代,Kubernetes 已成为云原生时代的标准操作系统,那么如何构建一个稳定自愈的云原生操作系统事关重大。尤其是分布式环境下,各类硬件和软件故障已成为常态,直接导致 Kubernetes 集群工作节点时常处于一种不稳定的状态,人肉运维不仅效率低下,误操作及 24 小时 OnCall 也是巨大的挑战,因此容器服务通过托管节点池为用户提供了一个自愈的免运维的云上 Kubernetes 集群服务。本文将重点介绍如何通过托管节点池实现 Kubernetes 节点自愈能力。
首先,我们需要定义什么是节点自愈?
什么是节点自愈?
Kubernetes 集群作为一个典型的分布式系统,是由一组 Master 管控节点,加上若干个运行工作负载的节点组成。其中若干个具有相同特性的节点逻辑上组成一个节点池,如果某个节点池的节点运维及生命周期管理由容器服务托管,则称该节点池为托管节点池。
节点自愈定义在 K8s 节点池之上,指无需人为干预,工作节点即可自行从故障状态中恢复。因此节点自愈的一个核心问题是故障状态处置及其恢复。 比如硬件故障(内存板卡损坏、磁盘坏道、网卡控制器故障)、软件故障(软件 OOM、进程句柄泄露、IO hang、磁盘满、网络断链)、机房断电跳闸、光缆故障、系统负载过高等。
由此我们抽象了几类故障层次。
- 瞬时故障(网络抖动,负载升高,应用请求超时,组件 OOM,异常重启)。
- 持续故障(环境变化触发未预期状态)。
- 错误(配置错误,误操作,逻辑 Bug。该类型错误可能被立即反应,也可能会很久后才能反应,它的特点是需要人为的知识干预,即使替换副本也无法解决,智能决策,智能纠错)。
瞬时故障通常在外部条件恢复后自行恢复,此类故障通常会在能触发响应之前已经恢复。
持续故障通常是我们需要人为干预的,通常预示着系统发生了某些比较严重的问题,需要专家经验介入,通常可以通过自动化的手段应对,属于本文关注的重点,也是自愈的范畴。
错误层需要意识的参与,比如配置错误,逻辑 Bug,没有意识参与修复,最终仍然会向错误的方向演化,因此不在本文讨论范围之内。
为什么需要自愈?
自愈的一个出发点是,基础设施是不稳定的;系统环境是不断变化的,不确定的,因此随时可能发生故障,需要 24 小时待命,干预修复,这对运维提出了非常大的挑战,因此构建一个自恢复、免运维的 Kubernetes 节点管理体系意义重大。
自愈的价值:
- 自愈的核心出发点是免运维,将工作人员从繁重的运维事务中解放出来,让他们专注于创新和更高价值的工作,相信半夜被故障报警折腾起来是每个运维人员都经历过的痛。
- 规模化集群的运维效率,提高人效与时效。(一个节点的运维与一万个节点的运维在时间上与工作量上具有本质的区别,大规模的节点故障已完全超出了人肉运维的可控范围,保姆式的运维是人力资源的极大浪费,成本昂贵)。
- 自动感知节点故障,相比于人肉运维具有更短的响应时间,在故障被终端用户感知前自行恢复。
- 程序化的工作能解决人为误操作引发的故障。
节点的自愈能显著提升运维效率(时效与人效、降本),降低人为误操作导致的问题,加速应用业务创新。
节点自愈的演进
1. 第一阶段:基于专家经验的进化
自愈的第一种方式是基于专家经验,将专家经验应用于自愈系统是最显而易见的方案。
专家经验方案是指将过往的专家运维经验打包成规则列表,形成故障到解法的预案,当匹配到具体故障的时候触发对应的修复方案。
图 1 专家经验
基于专家经验的好处是,一线运维人员对故障的细节最清楚,因此也成功总结了相应故障解决方案的最优流程,精准把控细节。但不能忽视的一个缺点就是:专家经验的覆盖面是相当有限的,不能覆盖未知故障的解法,而现实场景中已知的故障场景会慢慢收敛,未知故障会逐渐增多,这就造成专家经验会逐渐滞后,从而自愈的效果会被大打折扣。
那么是否有更加统一的方案来覆盖尽可能多的场景,同时又不会带来经验滞后问题呢?
自愈问题的本质(自愈困境)
这里我们需要探寻一下自愈难度大的根源。从一个开发运维熟知的 Devops 例子开始。
我们在讲 DevOps 的时候会强调开发测试和运维的鸿沟,运维抱怨应用没有充分测试就提交部署,而开发则抱怨我这里明明运行的好好的一定是你的使用姿势不对,然后经过一番痛苦的排查后,会发现问题是开发和运维运行应用的环境差异导致的,这样的事情在 Devops 时代频繁发生。Docker 的出现为开发和运维屏蔽了这个问题,docker 通过标准的镜像格式,将应用依赖的运行时环境统一打包成标准镜像作为交付,完美解决了这个环境问题。当然,里面还涉及其他的一些应用运行时标准。 当我们回头看看构建持久稳定的自愈系统时,其实也面临着同样的问题。运行时环境的变化给系统带来了极大的不确定性,这种不确定性(或者叫环境变化)是自愈难度大的根源。系统在运行的过程中会产生不稳定性,系统垃圾、未处理告警堆积、代码 Bug 累积、未处理的边缘异常 Case、一些人为故障源、都会引发的系统 Fail,无法穷举这些不确定性进一步决定了不可能 100% 的覆盖所有修复 CASE,因此需要人为时刻照看。
所以我们说自愈难度大,原因在于我们无法事先穷举所有可能的故障,也就无法完全覆盖故障解法。并且维护复杂多样的自愈方案对人类的脑容量来讲将会是灾难。千奇百怪的故障总会突破任何一个人脑容量的上限。
2. 第二阶段:基于 Replaceable 的重生
因此,如果想要解决这个问题,我们就需要转换思路。我们不需要穷举每个可能引发故障的 Case 逐个修复,只需要在故障发生的时候驱逐故障节点上的应用,然后使用一个全新的标准副本简单地替换掉故障源即可。
全新的副本替换与重置方式无需考虑复杂而未知的错误,只需要确认错误属于同一类别即可,因此能显著的缩小自愈的问题域,求解的复杂度大大降低。
与标准的 docker 镜像异曲同工之处在于,他们都使用标准的环境来重新初始化节点,这样不会有运行时的 Surprise,结果可预期。
下图是 K8s 集群下节点自愈的整体方案架构:
这里我们有意淡化故障的发现方式、面向不同基础设施的控制通道、metrics 收集、智能决策、任务编排等介绍,这是一些自愈方案的共性要素。我们重点关注修复方案,即精细化的专家经验修复(Pets)还是副本替换与重置(Cattle)。
这也是 Kubernetes 哲学基础,也是我们常说的 Cattle vs Pet. 节点资源在集群中应当被当做标准化的副本(无差别 Box),因此故障副本替换与重置是最经济成本的方式,最能达到效用最大化。
副本替换与重置的挑战
副本替换与重置方案会使用一个干净的副本重新初始化节点,其结果可控(参考 Docker 镜像的思路)。它能够保证提供一个全新的运行时环境,一个工作符合预期的集群,符合最终一致性原则。同时相比于专家经验能够覆盖更加广泛的故障场景,结果可控。
但同时也面临着两大重点挑战:
第一个是时间成本,当节点替换能够在 1s 内完成,这可以称为几乎没有成本,当副本的替换需要 5 分钟才能完成的话,我们会觉得这简直不可忍受,还是原地修一下更快。那么造成这种差异的因素又是什么呢?没错,就是人们的预期:对于不同故障判定时间的预期,修复故障所花费时间的预期。所以你的系统在故障持续多久后会失去耐心?这需要我们尽可能降低副本替换与重置的时间成本,比如副本要足够轻量,使替换的时间成本可控。 第二个是业务代价。副本替换是否会造成业务的抖动、中断?这个影响在多大程度上是我们能够接受的?是否有解决业务影响的相关方案。一般业务影响的来源主要有几个方面,应用被重启后已有连接会被迫中断,应用重启中间状态可能丢失,应用迁移时未保存的临时数据丢失等。因此需要应用在设计上能够容忍重启,具备响应驱逐信号的能力。
从另一个角度来说,即使不做副本替换,故障一定还会存在,业务代价也不会消除,所以最坏的情况是副本替换不会让事情变的更糟。
那么如何降低业务代价呢?
答案是构建一套全新的云原生应用标准,面向失败的应用设计。必须假定环境是不可信的,随时面临故障重启迁移等等,需要定义并解决流量平滑迁移,数据与状态迁移等的标准。但这仍然有一段很长的路要走,也是未来智能化的必经之路。
3. 混合方案
专家经验和副本替换并不是两种水火不容的方案,它们各有优点,因此我们可以充分取长补短,对于已知的问题我们通过精细化的专家经验方式执行修复,能充分保留原有节点的状态(临时数据、长连接等);当故障范畴已超出专家经验库的时候,我们启动应用驱逐与故障副本替换的方式来尝试兜底修复,从而保证系统的稳定性、业务的连续性。
容器服务 ACK 托管节点池通过这种混合的方式实现了灵活可配置的节点自愈,让用户从节点的运维中解放出来,对应用提供一个统一的池化视图,无需关心底层基础设施。
自愈的未来
1. 节点自愈 vs 集群自愈
我们今天重点讨论的是节点维度的自愈,如果我们跳出节点维度,在更大的范围看待这个事情,是否也有同样的效果?比如集群维度(集群自愈)、PaaS 维度(PaaS 自愈)、公共云维度(公共云自愈)。
如果每个维度都是一个无差别化的副本,那么通过副本替换与重置是否能达到最佳的自愈效果?如何解决时间成本与业务代价?那些我们曾经以为绝对不可能的事,是否也会随着技术的进步被一次次突破?比如 IP 地址数、内存地址。
因此,未来不仅仅是节点的自愈,不仅仅是节点的 Replaceable。
2. 应用标准化
应用标准化是自动化到智能化的前提。每个应用、每个节点、每个集群在地位上都是对等的,标准的规格、标准的集装箱。
没有规矩不成方圆,一套全新的云原生应用标准势在必行,让应用的重启、流量的平滑迁移、数据状态存储与迁移成为常态,应用标准化促成规模效应。应用的标准化为自愈提供坚实的实践基础。
3. 构建智能化的系统
智能化是系统发展的终态,从工具的发展可以看尽人类的发展史,我们的终极目标就是发明一个工具可以为我们发明工具,这便是智能化。自动化运维让我们向智能化的方向迈进了一小步,自愈是则是自动化的排头兵。
一个高度自治的系统,会形成系统自愈的闭环,故障的发现到隔离,替换或重置修复,可以是软件故障的修复,甚至可以是硬件故障的自我替换。或许是人类指导人工智能,也可能是人工智能指导人类的决策。总之,系统会自我驱动运行。
托管节点池详细信息请参考文档。