从Kubernetes的探针到DevOps

今天在群里又看有人问如何设置 Kube.NETes 的探针,感觉要补充的话太多了,结合我们在一些 DevOps 项目中痛苦的体验,今天一劳永逸的全部说完,此外,也为大家展现一下为什么 DevOps 这么难?
探针的作用从功能上讲,探针的作用很简单,之前我也发文澄清过许多人的一些概念不清,本文是希望让运维和开发都能理解,所以会尽量简单的表达 。
探针功能是 Kubernetes 提供的一个侦测应用是否正常运行的检查机制 。最常见的探测方式是 HTTP 探测 。应用需要暴露一个地址,Kubernetes 会定期调用该地址,如果地址返回 200 状态码,则认为应用正常,否则认为应用异常 。
一般情况下会需要为应用配置两个探针,分别是存活(liveness)探针和就绪(readiness)探针 。存活探针可以在应用有问题时触发重启 , 应用在重启后可能可以恢复正常 。而就绪探针,保证应用有问题时切断流量,避免该应用被调用到:
 

从Kubernetes的探针到DevOps

文章插图
图片
 
如果只是从功能角度看 , 似乎二者的区别不大,配置一个相同的应用接口似乎也没啥问题 , 那为什么还要设置两个不同的探针呢?“假设” Kubernetes 的开发者是理智的,则肯定有原因,这个原因后面详细说,先看看运维面临的问题 。
宏观的意义运维的朋友,尤其是做过微服务应用运维的朋友 , 一定见识过某个基础组件或上游服务出故障的情况吧?可观测做的“到位”,可能是满大屏的红色惊叹号 。《发布!设计与部署稳定的分布式系统》书中将这个稳定性反模式叫做“级联效应” 。
产生级联效应的过程,可以用下图来展示:
 
从Kubernetes的探针到DevOps

文章插图
图片
 
当上游的 Pod 不可用时,其下游的 Pod 也无法工作,然后传播到所有相关的 Pod 中 。
此时此刻,如果可观测工具将所有的错误一股脑的抛出来,运维人员一定会感到非常的绝望,一定希望有一个工具可以告诉他:某个 Pod 本身出问题了 , 其他 Pod 是因为依赖的 Pod 出问题了所以报错了 。这样才能能专注于解决关键问题 。
此外,这种级联反应的故障恢复时,也往往绝非“病去如抽丝”,可能不断会遇到个别的业务问题,有时运维人员需要去手工重启服务才能解决 。他一定希望:应用要是能够在条件具备时自动恢复就好了 。
没错,解决这两个需求的方法就是探针 。
探针如何发挥作用这两个探针正是 Kubernetes 平台与应用之间沟通的契约,当返回报错时,应用实际要表达的意思和做出的承诺是:
  • 存活探针: 我不行了,多试几次 , 如果还不行,就干掉我重启试试 。
  • 就绪探针:我现在没法对外提供服务,不要将请求转给我 。可能是我依赖的服务有异常,如果依赖的服务恢复,我应该也能恢复 。
这样看,两个探针有着明显的区别 。而这两个探针与应用配合,是如何解决上一章所说的问题呢?
首先说说应用完全hang死的情况 。此时无论是存活探针还是就绪探针,都会探测异常 , 肯定会触发重启 , 这种情况在应用也没法做什么预设 , 是探针机制最立竿见影的一个情况 。
当应用本身发生问题时,存活探针应该报告异常 , 从而触发重启 。此时,问题的关键是,应用如何知道自己存在异常?确实挺难的,这个探针对应的接口应该能够模拟正常业务的主要逻辑,而且如果依赖的服务有问题,而且应用能够处理这个问题 , 则不应该报告异常 。
当应用依赖的服务出现故障时 。我们希望应用的存活探针报告正常 , 而就绪探针报告报告异常 。因为此时存活探针报告异常触发了应用重启也解决不了任务问题 , 大量的重启以及相关的报错反而会让运维人员感到恐慌 。探针这样工作有一个非常重要的前提条件,那就是应用在其依赖服务恢复时也能够自己恢复 。如果应用无法自动恢复,也许我们只能选择让存活探针在此时报告异常,运维需要面对反复重启的无尽惶恐之中 。
问题到了开发这里道理都懂了 , 但是该如何解决呢?对运维来说意义重大的一个功能,却必须依靠开发人员来完成 。首先,需要开发人员理解上述过程,这也是编写本文的目的之一,然后就是去实现了 。


推荐阅读