前言

本文主要会介绍笔者在学习Kubernetes Pod的恢复策略与容器健康检查时所总结的知识点,其中会涉及到容器状态、容器恢复策略、容器探针检查方式以及恢复策略与健康检查的配合使用等方面的相关内容。 笔者也会将自己的理解在文中进行阐述,这也算是在和大家交流心得的一个过程。若文中有错误的理解和概念,请大家及时纠正;吸纳大家的建议,对于我来说也是很重要的学习过程之一。


(目录)


1.容器状态

Kubernetes会跟踪记录Pod中每个容器的状态。

注意:请务必不要将Pod的阶段状态与容器状态的概念混淆。两者的阶段定义上是有些相似,但本质上关注的是两种对象的运行状态。

06_03.png

容器的状态有三种:Waiting(等待)、Running(运行中)和 Terminated(已终止)。

Tips: 具体的关于容器状态的知识,可以阅读笔者另一篇文章中的相关章节

后续所介绍的容器恢复策略以及容器健康监测,实际上都是围绕着容器状态来展开的


2.容器恢复策略

2.1 配置方式

Pod的恢复策略是通过Pod中一个属性来进行设定的,即pod.spec.restartPolicy。

pod.spec.restartPolicy字段的取值有以下三种:

  1. Always(默认) 在任何情况下,只要容器不在Running状态就会自动重启容器。

  2. OnFailure 只有容器异常时才自动重启容器。

  3. Never 无论容器处于何种状态,Kubernetes都不会自动重启容器。即永远不会重启容器

2.2 恢复细节

Pod的恢复过程永远都是发生在当前节点上,而不会跑到别的节点上去。即kubulet只会负责重启其所在node上的Pod

实际上,一旦一个Pod与一个Node绑定后,除非这个绑定发生了变化(即pod.spec.node属性被修改),否则Pod永远都不会离开这个节点。即使该Node宕机了,这个Pod也不会主动迁移到其他节点上去。如果想移动Pod,就必须使用 Deployment这样的controller来管理Pod。controller本身就是在动态修改pod.spec.node字段,以来实现对Pod的动态迁移。

2.3 恢复机制与Pod状态

只要pod.restartPolicy指定的策略允许重启异常的容器(比如:Always),那么这个Pod就会保持Running状态;否则Pod就会进入Failed状态。

Tips: 关于Pod状态的更多细节,可以参考读者的另一篇文章

2.4 工作原理

pod.restartPolicy作用于Pod中的应用容器和Init容器。对于异常退出的Init容器,如果pod.restartPolicy为 OnFailure或Always,则kubelet会重新启动Init容器。 对于Sidecar容器(v1.28版本后)忽略pod.restartPolicy。在Kubernetes中,Sidecar被定义为 initContainers 内的一个条目,其恢复策略被设置为Always。

restartPolicy适用于Pod中的所有容器。当kubelet根据配置的重启策略对容器进行重启操作时,只会操作kubelet当前所在node上指定Pod中的容器。kubelet 会按指数回退方式计算重启的延迟(10s、20s、40s、...),其最长延迟为 5 分钟。 一旦某容器执行了 10 分钟并且没有出现问题,kubelet 对该容器的重启回退计时器执行重置操作。


3.容器健康检查

3.1 检查机制

Kubernetes使用容器探针来检查Pod中容器的健康状态。

options.png

目前支持以下几种探测的实现方式:

  1. exec 即在容器内执行使用shell实现的健康监测命令/脚本,如果命令退出时返回码为0则认为容器是健康的。

  2. grpc 使用gRPC执行一个远程过程调用,这种方式要求目标应该实现一个基于gRPC的健康检查方法。如果响应的状态是 "SERVING",则认为容器是健康的。

  3. httpGet 对容器的IP地址和指定端口号发送一个HTTP GET请求,即要求容器内部的需要实现一个基于HTTP的健康监测API。如果响应的状态码大于等于 200 且小于 400,则认为容器是健康的。

  4. tcpSocket 对容器的IP地址上的指定端口执行TCP检查。如果端口打开,则认为容器是健康的。如果远程系统(容器)在打开连接后立即将其关闭,也算作是健康的。

Tips: 对于选取哪种探测方式,笔者给出一些建议。如果研发团队能够给予一定义的配合支持,则建议选取grpc或httpGet的方式进行探测;因为可以将容器的健康监测API和业务的健康监测API合并在一起实现,并且还有助于统一健康监测API的实现规范。 若研发团队无法为业务应用添加健康监测API并且业务应用是以service形式实现的,则建议选择tcpSocket来进行探测。 如果业务应用是类似于后台服务的独立运行单元,则建议选择exec方式来进行探测;可针对业务应用的日志文件或产出文件来进行探测验证。

探针进行探测后的返回结果的取值范围是:

  1. success
  2. failure
  3. unknown

3.2 探针类型

kubernetes-probes.png

3.2.1 livenessProbe

livenessProbe即存活探针,其主要用于负责保证容器是否能够正常运行

3.2.1.1 工作原理

kubelet会根据探针的返回值决定这个容器的状态,而不是直接以容器镜像是否运行(来自 Docker 返回的信息)作为依据。kubelet定期调用容器中的LivenessProbe探针来诊断容器的健康状况。

该探针如果探测失败则会通知kubelet会杀死容器并且容器将根据其重启策略进行相关操作。如果不配置该探针,则默认认为该探针返回success。

3.2.1.2 适用场景

如果希望容器在探测失败被kill后还能重新启动,那么建议添加一个livenessProbe探针并配合相应的容器重启策略。

Tips: 如果容器中的进程在遇到问题或不健康的情况下能够自行崩溃(即以非0 code退出),则不一定需要存活态探针。因为如果配置相应的容器恢复策略,则kubelet将根据恢复策略自动执行修复操作。

3.2.2 readinessProbe

readinessProbe负责保证容器是否能够对外提供正常的业务服务

3.2.2.1 工作原理

该探针如果探测失败,Endpoint Controller会在相应Service对象所关联的多个Endpoint对象中删除包含该容器所在Pod的IP地址的Endpoint对象。即readinessProbe检查结果的成功与否,决定的这个Pod是否能被通过 Service的方式访问到,而并不影响Pod的生命周期

如果不配置该探针,则默认认为该探针返回success。

3.2.2.2 适用场景
  1. 自动屏蔽异常业务容器 如果需要保证服务正常启动后才将请求流量导入到其上,则可以选择使用readinessProbe。即防止正常的请求流量流入有问题的容器(服务)中。

  2. 支持维护模式 如果服务或应用程序提供切换到维护模式的功能,此时可以为其配置readinessProbe。即当应用服务切换到维护模式后,使探针的探测结果始终为failure;退出维护模式后,探测结果变为success。

  3. 按照服务状态分类 如果想区分已经失败的应用和仍在处理其启动数据的应用,此时可以使用readinessProbe。即可以统计服务中有哪些能够正常对外提供服务,哪些是不能异常的。

Tips: 如果只是想在Pod被删除时能够不再接收请求,则不一定需要使用就绪态探针。因为此时Pod会被自动设置为未就绪状态。

3.2.3 startupProbe

startupProbe即启动探针,startupProbe是在Kubernetes v1.18中新增的一种探针类型。

3.2.3.1 工作原理

该探针如果探测失败,则会通知kubelet会杀死容器并且容器将根据其重启策略进行相关操作。同时,该探针在工作时其他探针都会被禁用。 如果不配置该探针,则默认认为该探针返回success。

3.2.3.2 适用场景
  1. 容器需要有较长启动时间 在startupProbe还没有出现之前,对于这种启动时间过长的容器往往都需要配置一个探测时间间隔较长的livenessProbe来对其进行存活监测。而startupProbe出现后,就可以为这类容器配置一个startupProbe类型的探针即可。 通常,但容器的启动时间超出initialDelaySeconds + failureThreshold × periodSeconds总值时,可以考虑设置一个startupProbe探针了。

  2. 解决livenessProbe的死锁问题 当livenessProbe的等待时长设置的不合理时,有可能会让Pod产生死锁状态。即livenessProbe在探测的时间间隔小于容器启动市场时,就会发生探测一直失败从而导致Pod一直在被重启。 这类问题往往是由于容器启动的时间过长导致,此时通过添加一个相同配置的startupProbe,就可以解决死锁问题。即livenessProbe和startupProbe配合使用,可解决启动时间过长的容器死锁状态问题

3.3 探针相关配置

3.3.1 通用配置参数

6.6.png

livenessProbe与readinessProbe还可配置如下几个参数:

  1. initialDelaySeconds 容器启动后要等待多少秒后才调用livenessProbe和readinessProbe进行探测。默认是 0 秒,最小值是 0。

  2. periodSeconds 执行探测的时间间隔(单位是秒)。默认是 10 秒。最小值是 1。

  3. timeoutSeconds 如果探测超时,则需要等待多少秒。默认值是 1 秒。最小值是 1。

  4. successThreshold 探测器在失败后被视为成功的最小连续成功数,默认值是 1。livenessProbe和readinessProbe的这个值必须是1,最小值是 1。

  5. failureThreshold 当探测失败时探测重试次数。对于livenessProbe,如果不进行重试就意味着重新启动容器。对于readinessProbe,如果不进行重试就意味着Pod会被打上未就绪的标签。默认值是 3,最小值是 1。

3.3.2 readinessProbe httpGet探测配置参数

针对于httpGet探测,可添加如下几个配置:

  1. host 连接使用的主机名,默认是 Pod 的 IP。也可以在 HTTP 头中设置 “Host” 来代替。

  2. scheme 用于设置连接主机的方式(HTTP 还是 HTTPS)。默认是 "HTTP"。

  3. path 访问 HTTP 服务的路径。默认值为 "/"。

  4. httpHeaders 请求中自定义的 HTTP 头。HTTP 头字段允许重复。

  5. port 访问容器的端口号或者端口名。如果数字必须在 1~65535 之间。

Tips: tcpSocket探测和httpGet探测配置类似。

3.3.3 startupProbe配置

可通过将failureThreshold * periodSeconds参数设置为足够长的时间来应对极端的"长启动"情况。periodSeconds 的默认值是 10 秒。可将 failureThreshold 设置得足够高,以便容器有充足的时间完成启动,并且避免使用过长探测间隔的livenessProbe。