--昨夜西风凋碧树,独上高楼,望尽天涯路
自愈能力是Kubernetes一个强大的特性,自愈的默认实现方式是自动重启发生故障的容器,除此之外,还可以利用Liveness和Readiness探测机制设置更精细的健康检查。
有了这个强大的特性可以实现强大的需求:
1)零停机部署
2)避免部署无效镜像
3)更加安全的滚动升级
-
默认健康检测
每个容器启动的时候都会执行一个进程,由Dockerfile的CMD或者ENTRYPOINT指定。程序正常退出的时候会返回一个为零的返回码,当返回码非零的时候则认为容器发生故障,这个时候Kubernetes可以配置重启策略,进行容器重启。
模拟一个故障发生场景,启动一个busybox应用,每隔10秒退出一次,由于容器不是正常退出进程返回值非零,Kubernetes会认为容器发生了故障,需要重启(将restartPolicy设置为OnFailure,失败时重启。默认为Always):
过一段时间后查看pod状态,发现已经重启了5次:
-
Liveness探测
在很多情况下应用发生故障但是进程不会退出。比如访问Web服务器时显示500内部错误,可能是系统超载,也可能是资源死锁,此时httpd进程并没有异常退出,这种情况下重启容器可能是最直接和最有效的办法。这种情况可以使用Liveness来处理。
Liveness探测可以自定义判断容器是否健康的条件。如果探测失败,自动重启容器。创建应用:
启动一个busybox应用,再busybox中创建文件/tmp/healthy,30秒之后删除。之后等待600秒。
liveness的探测机制为cat /tmp/healthy文件(initialDelaySeconds指定10秒之后开始执行探测,periodSeconds指定每隔5秒执行一次,Kubernetes如果3次探测失败,则会重启容器)
通过kubectl apply -f liveness.yml启动应用之后,通过kubectl describe pod liveness查看:
发现35秒之后文件不存在,Liveness探测失败,失败3次之后开始重启容器
查看Pod,发现已经被重启:
-
Readiness探测
Liveness告诉Kubernetes什么时候重启容器自愈;Readiness探测则是告诉Kubernetes什么时候可以将容器加入到Service负载均衡池中,对外提供服务。
创建应用(该配置文件和Liveness相似,只需要该Liveness为Readiness):
查看Pod(刚创建时不可用,19秒的时候探测成功设置为可用,之后会连续探测3次,均失败后设置为不可用):
通过kubectl describe pod readiness查看探测失败日志:
比较两种探测:
相同点:两者都是Health Check机制,如果不特意配置,Kubernetes将对两种探测采取相同的默认行为,即通过判断容器启动进程的返回值是否为零来判断探测是否成功;配置方法完全一样,支持的配置参数也一样;Liveness探测和Readiness探测都是独立执行的,二者没有依赖,可以单独使用也可以同时使用。
不同点:探测失败后的,Liveness探测是重启容器,Readiness探测则是将容器设置为不可用,不接收Service转发的请求。
总结:Liveness探测判断是否需要重启容器以实现自愈;Readiness探测判断容器是否已经准备好对外提供服务。
-
实战Health Check
滚动更新时,Kubernetes会启动新副本逐渐替换旧副本,但是当启动新副本的时候会出现如下问题:
1)新副本在启动成功之前无法相应业务需求
2)由于配置错误导致新副本无法完成准备工作(比如无法链接缓存或者数据库)
由于新副本没有异常退出,默认的Health Check机制会认为容器已经就绪,进而会逐渐用新副本替换现有副本,最后当所有旧副本被替换之后会导致系统不可使用。
配置Readiness探测,新副本只有通过了检查才会被添加到Service
运行如下应用:
由于存在/tmp/healthy文件,10秒之后Readiness探测成功,部署成功:
修改yml配置滚动更新:
查看部署信息发现杀死了两个旧副本,重启了5个新副本,但是新副本都处于NOT READY状态,证明Readiness探测成功:
通过kubectl describe deployment app查看,发现到第一次替换就已经卡住:
通过kubectl rollout undo回滚到上一版本: