今天在群里又看有人问如何设置 Kubernetes 的探针,感觉要补充的话太多了,结合我们在一些 DevOps 项目中痛苦的体验,今天一劳永逸的全部说完,此外,也为大家展现一下为什么 DevOps 这么难?
探针的作用
从功能上讲,探针的作用很简单,之前我也发文澄清过许多人的一些概念不清,本文是希望让运维和开发都能理解,所以会尽量简单的表达。
探针功能是 Kubernetes 提供的一个侦测应用是否正常运行的检查机制。最常见的探测方式是 HTTP 探测。应用需要暴露一个地址,Kubernetes 会定期调用该地址,如果地址返回 200 状态码,则认为应用正常,否则认为应用异常。
一般情况下会需要为应用配置两个探针,分别是存活(liveness)探针和就绪(readiness)探针。存活探针可以在应用有问题时触发重启,应用在重启后可能可以恢复正常。而就绪探针,保证应用有问题时切断流量,避免该应用被调用到:
图片
如果只是从功能角度看,似乎二者的区别不大,配置一个相同的应用接口似乎也没啥问题,那为什么还要设置两个不同的探针呢?“假设” Kubernetes 的开发者是理智的,则肯定有原因,这个原因后面详细说,先看看运维面临的问题。
宏观的意义
运维的朋友,尤其是做过微服务应用运维的朋友,一定见识过某个基础组件或上游服务出故障的情况吧?可观测做的“到位”,可能是满大屏的红色惊叹号。《发布!设计与部署稳定的分布式系统》书中将这个稳定性反模式叫做“级联效应”。
产生级联效应的过程,可以用下图来展示:
图片
当上游的 Pod 不可用时,其下游的 Pod 也无法工作,然后传播到所有相关的 Pod 中。
此时此刻,如果可观测工具将所有的错误一股脑的抛出来,运维人员一定会感到非常的绝望,一定希望有一个工具可以告诉他:某个 Pod 本身出问题了,其他 Pod 是因为依赖的 Pod 出问题了所以报错了。这样才能能专注于解决关键问题。
此外,这种级联反应的故障恢复时,也往往绝非“病去如抽丝”,可能不断会遇到个别的业务问题,有时运维人员需要去手工重启服务才能解决。他一定希望:应用要是能够在条件具备时自动恢复就好了。
没错,解决这两个需求的方法就是探针。
探针如何发挥作用
这两个探针正是 Kubernetes 平台与应用之间沟通的契约,当返回报错时,应用实际要表达的意思和做出的承诺是:
- 存活探针: 我不行了,多试几次,如果还不行,就干掉我重启试试。
- 就绪探针:我现在没法对外提供服务,不要将请求转给我。可能是我依赖的服务有异常,如果依赖的服务恢复,我应该也能恢复。
这样看,两个探针有着明显的区别。而这两个探针与应用配合,是如何解决上一章所说的问题呢?
首先说说应用完全hang死的情况。此时无论是存活探针还是就绪探针,都会探测异常,肯定会触发重启,这种情况在应用也没法做什么预设,是探针机制最立竿见影的一个情况。
当应用本身发生问题时,存活探针应该报告异常,从而触发重启。此时,问题的关键是,应用如何知道自己存在异常?确实挺难的,这个探针对应的接口应该能够模拟正常业务的主要逻辑,而且如果依赖的服务有问题,而且应用能够处理这个问题,则不应该报告异常。
当应用依赖的服务出现故障时。我们希望应用的存活探针报告正常,而就绪探针报告报告异常。因为此时存活探针报告异常触发了应用重启也解决不了任务问题,大量的重启以及相关的报错反而会让运维人员感到恐慌。探针这样工作有一个非常重要的前提条件,那就是应用在其依赖服务恢复时也能够自己恢复。如果应用无法自动恢复,也许我们只能选择让存活探针在此时报告异常,运维需要面对反复重启的无尽惶恐之中。
问题到了开发这里
道理都懂了,但是该如何解决呢?对运维来说意义重大的一个功能,却必须依靠开发人员来完成。首先,需要开发人员理解上述过程,这也是编写本文的目的之一,然后就是去实现了。
尽管像 Spring 这样的开发框架,已经提供了探针相关的功能,开发可能配置一下就能完成,但实际情况往往并不简单。例如 spring 文档说了:
The “liveness” Probe should not depend on health checks for external systems.
意思就是 liveness 探针不应当依赖外部系统的状态,但实际上有时这个外部系统的定义未必那么笃定;也可能我们的应用无法从某个外部系统的故障中恢复,所以即使是外部系统,我们可能也会将其纳入到 liveness 探针需要检查的范畴。
而且,很有可能我们不能一次做好这个事情,需要在结合实际出现的问题进行调整。如果开发没有参与运维,或者中间的沟通不畅,亦或者没把这件是当做自己的事情,这个探针的问题未必能简单的解决。
其实群里人家问的是探针的参数问题,但其实这些参数只是控制故障能多快的暴露出来,如果应用的探针本身就有问题,这些参数设置的再精妙都没有意义。我觉得这是许多团队的一种工作状态:我们部门自己能搞定的尽量不要依赖别的团队。例如,要是我能找到一个可观测工具,直接给我定位哪个pod出问题,那我还找什么开发。
实际上呢?太难了,做这样包治百病的工具太难了。不过,根据许多人的选择,我们知道这可能比让 Dev 和 Ops 高效的配合起来更简单,至少没那么绝望吧。
谨以本文给大家一个例子,希望大家能够互相体谅,保持一点 DevOps 的精神,高层领导也能意识到这个问题,看看怎么解决。再就是看看平台工程,是不是可以建设一个好的平台,让开发能够更轻松的直面这个问题,毕竟自己写的程序最了解。
参考
- [1] 链式反应和级联故障:https://www.bilibili.com/video/BV13Q4y1K7FU/
- [2] 2.9.2. Application lifecycle and Probes states:https://docs.spring.io/spring-boot/docs/2.4.1/reference/html/production-ready-features.html#production-ready-kubernetes-probes-external-state
- [3] 探针对于伸缩的意义和一些参数说明https://yylives.cc/2023/02/25/kubernetes-probes-and-why-they-matter-for-autoscaling/