Docker 健康检查的目的、影响和处理
Docker 健康检查的目的、影响和处理
引言
网上关于 docker 的教程往往只会讲容器、镜像、网络、数据卷。对于健康检查往往只是一笔带过:在 Dockerfile 中写一个 healthcheck 命令,然后看到容器状态变成了“healthy”就万事大吉。而对于不健康的容器会造成什么影响、如何处理不健康的容器则很少提及。
如果想充分发挥容器化的健壮性优势,我们就需要认真审视 docker 提供的健康检查功能。
为什么需要健康检查?
默认情况下,docker 判断一个容器是否存活的方式是通过检测容器内 pid = 1 的进程是否存活(这个进程就是 Dockerfile 的 entrypoint 中启动的进程),这个检查方式非常粗放,因为有时容器已经失去了正常对外提供服务的能力,但是进程仍然存活。
鉴于以上的情况,容器的健康状态应该由用户定义。
常见的检测方案是应用本身暴露一个 http 接口,用于表示自己是否健康,然后通过定时检查访问该接口来判断应用的健康状态。(详见 spring actuator)
这样,我们就可以判断哪些容器是健康的,那些是不健康的。
当一个容器不健康时,会发生什么?
我们知道,处于同一个 docker 网络中的容器可以通过容器名代替 dns 名称进行互相访问。容器名会被解析为对应的 ip 地址。
在进行 dns 解析时,不会返回不健康的容器的 ip,dns 解析会因为得不到正常结果而失败。
你可以认为这是 docker 实现的“服务熔断”:不健康的容器不允许提供服务。
如果这是一个被反向代理(使用 traefik 或 nginx proxy manager)的 http 服务,你会发现服务无法访问,这是因为网关无法访问到不健康的容器。
如何处理不健康的容器?
docker 不会对 unhealthy 状态的容器进行任何处理。
我们的常见思路是重启,但是这要依赖另一个开源软件:https://github.com/willfarrell/docker-autoheal
这个软件非常简单,只需要挂载 docker socket 文件,即可自动检查并重启不健康的容器。
当然,一些故障是重启无法解决的,必须要人工介入,我们可以使用 prometheus + alertmanager 的方式及时发现服务异常并告警,用户可以自定义告警通知方式(邮件、webhook 以及其驱动的各种机器人)
总结
本文介绍了 docker 健康检查机制诞生的目的、容器不健康时的影响以及如何处理不健康的容器。