前言

网上关于 Docker 的教程往往只会讲容器、镜像、网络、数据卷。对于健康检查往往只是一笔带过:在 Dockerfile 中写一个 HEALTHCHECK 命令,然后看到容器状态变成了 “healthy” 就万事大吉。而对于不健康的容器会造成什么影响、如何处理不健康的容器则很少提及。

如果想充分发挥容器化的健壮性优势,我们就需要认真审视 Docker 提供的健康检查功能。

结论先行

Docker 健康检查是保障容器化应用可靠性的关键机制。 不健康的容器会被 Docker 网络自动隔离,但 Docker 本身不会重启它们。我们需要结合 autoheal 工具实现自动重启,并通过 Prometheus + Alertmanager 实现告警监控。

为什么需要健康检查?

默认检查方式的局限性

默认情况下,Docker 判断一个容器是否存活的方式是通过检测容器内 PID = 1 的进程是否存活(这个进程就是 Dockerfile 的 ENTRYPOINT 中启动的进程)。

这个检查方式非常粗放,因为有时容器已经失去了正常对外提供服务的能力,但是进程仍然存活。例如:

  • 应用陷入死锁,无法响应请求
  • 数据库连接池耗尽,无法处理新请求
  • 内存泄漏导致 GC 频繁,响应缓慢

用户自定义健康状态

鉴于以上的情况,容器的健康状态应该由用户定义

常见的检测方案

应用本身暴露一个 HTTP 接口,用于表示自己是否健康,然后通过定时检查访问该接口来判断应用的健康状态。

示例:Spring Boot Actuator 提供的 /actuator/health 端点。

这样,我们就可以准确判断哪些容器是健康的,哪些是不健康的。

当一个容器不健康时,会发生什么?

Docker 网络的自动隔离

我们知道,处于同一个 Docker 网络中的容器可以通过容器名代替 DNS 名称进行互相访问。容器名会被解析为对应的 IP 地址。

关键机制

在进行 DNS 解析时,不会返回不健康的容器的 IP,DNS 解析会因为得不到正常结果而失败。

你可以认为这是 Docker 实现的**”服务熔断”**:不健康的容器不允许提供服务。

对反向代理的影响

如果这是一个被反向代理(使用 Traefik 或 Nginx Proxy Manager)的 HTTP 服务,你会发现服务无法访问,这是因为网关无法访问到不健康的容器。

如何处理不健康的容器?

Docker 的默认行为

重要:Docker 不会对 unhealthy 状态的容器进行任何处理。

自动重启方案:docker-autoheal

我们的常见思路是重启,但是这要依赖另一个开源软件:

项目地址https://github.com/willfarrell/docker-autoheal

工作原理

这个软件非常简单,只需要挂载 Docker socket 文件,即可自动检查并重启不健康的容器。

使用示例

1
2
3
4
5
6
7
8
9
version: '3'
services:
autoheal:
image: willfarrell/autoheal
restart: always
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- AUTOHEAL_CONTAINER_LABEL=all

告警监控方案

当然,一些故障是重启无法解决的,必须要人工介入。我们可以使用 Prometheus + Alertmanager 的方式及时发现服务异常并告警。

告警方式

  • 邮件
  • Webhook
  • 各种机器人(钉钉、企业微信、Slack 等)

总结

主题 核心要点
健康检查的必要性 默认的进程存活检查不够准确,需要用户自定义
不健康容器的影响 Docker 网络会自动隔离,DNS 解析失败
自动重启 使用 docker-autoheal 工具
告警监控 使用 Prometheus + Alertmanager

Docker 健康检查机制是容器化应用可靠性的重要保障。通过合理配置健康检查、自动重启和告警监控,可以大大提升系统的稳定性和可用性。