当容器内的进程仍在运行,但应用已经无法响应请求时,Docker 默认会认为容器是健康的。这导致流量被转发到故障实例、滚动更新卡死、故障转移失效。容器健康检查机制正是为了解决这类问题而设计——它通过定期探测容器内的指定命令或 HTTP 端点,将容器标记为 healthy 或 unhealthy,从而让编排平台(如 Docker Swarm、Kubernetes)做出自动重启、停止接收流量等决策。本文从 Docker 原生 HEALTHCHECK 指令出发,逐步覆盖配置方法、状态查看、编排场景下的应用,以及常见误区。
健康检查的典型场景:为什么需要它
假设你运行着一个 Nginx 容器,进程始终存活,但配置文件损坏导致 502。此时 Docker 默认的进程存活检查无法发现问题。若没有健康检查,负载均衡器会继续将请求发给这个“活着但坏了”的容器。健康检查通过应用层探测(如 HTTP 请求)来区分“进程存活”和“服务可用”,是构建自愈系统的关键。
Docker 原生健康检查:HEALTHCHECK 指令
Dockerfile 中的 HEALTHCHECK 指令定义了容器启动后的检查命令。基本语法如下:
HEALTHCHECK [OPTIONS] CMD command
常用选项:
- –interval:检查间隔,默认 30 秒。
- –timeout:单次检查超时,默认 30 秒。
- –retries:连续失败次数达到该值则标记为 unhealthy,默认 3 次。
- –start-period:启动宽限期,容器启动后等待该时长才开始检查,默认 0 秒。
示例:对 Web 服务做 HTTP 健康检查。
HEALTHCHECK --interval=5s --timeout=3s --retries=3
CMD curl -f http://localhost/ || exit 1
命令退出码为 0 表示健康,非 0 表示不健康。注意镜像内需包含 curl 或 wget,否则需改用其他方式(如 wget、node 脚本)。
查看健康状态:docker inspect 与 docker ps
容器启动后,可通过 docker ps 的 STATUS 列看到 health 状态(healthy/unhealthy/starting)。更详细的信息用 docker inspect:
docker inspect --format='{{json .State.Health}}' <container>
输出包含检查日志、失败次数、上次输出等。若容器被标记为 unhealthy,Docker 本身不会自动重启它——除非你在编排环境(如 Swarm 服务)中配置了自动恢复策略。
在 Docker Compose 中配置健康检查
Compose 文件中的 healthcheck 键可覆盖 Dockerfile 中的定义,或为未定义 HEALTHCHECK 的镜像添加检查。示例:
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
注意:若镜像中没有 curl,可改为使用 wget 或使用 Docker 内置的检查工具(如 CMD-SHELL)。此外,Compose 中依赖健康状态的服务可用 depends_on 的 condition 字段(Compose 规范支持,但需确认版本)。
在 Kubernetes 中实现健康检查:liveness 与 readiness
Kubernetes 提供了两种探针,与 Docker HEALTHCHECK 互补:
- livenessProbe:决定是否重启容器。失败时 kubelet 会杀掉容器并重启。
- readinessProbe:决定是否将 Pod 加入 Service 的端点列表。失败时移除流量,但不重启。
配置示例:
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
containers:
- name: app
image: nginx
livenessProbe:
httpGet:
path: /healthz
port: 80
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /ready
port: 80
initialDelaySeconds: 3
periodSeconds: 5
Kubernetes 官方文档指出,Pod 是 Kubernetes 中最小的可部署计算对象,探针正是作用于 Pod 内容器的机制。实际场景中,liveness 失败会导致重启,readiness 失败仅摘除流量,二者应区分使用。
健康检查在编排中的实际作用
在 Docker Swarm 中,服务的 --health-cmd 等参数可定义健康检查,Swarm 会根据检查结果决定是否重启任务或停止发送流量。Kubernetes 中,Deployment 的滚动更新依赖 readinessProbe:只有新 Pod 就绪后才会继续更新,避免中断服务。此外,结合 OpenTelemetry 等可观测性工具,健康检查的失败日志可纳入监控体系,帮助定位问题。
常见误区与失败条件
- 只检查进程存活:进程存在不代表服务可用,必须做应用层探测。
- 检查命令依赖外部工具:镜像内未安装 curl 会导致检查永远失败,应使用镜像自带的工具或改用 HTTP 探测。
- 忽略 start-period:应用启动慢时,未设置宽限期会导致健康检查误判,容器被反复重启。
- 在 Kubernetes 中混淆 liveness 与 readiness:将业务依赖(如数据库)的检查放在 liveness 中,可能导致数据库抖动时整个容器重启,应使用 readiness 处理依赖故障。
- 健康检查过于频繁:间隔过短可能增加负载,尤其是高并发服务。
最佳实践与取舍
健康检查命令应轻量、快速,避免执行复杂逻辑。HTTP 端点应设计为只检查自身进程状态,不依赖外部服务,否则会引发级联失败。对于无 HTTP 服务的进程,可使用脚本检查关键文件或端口。在编排环境中,建议同时配置 liveness 和 readiness,并设置合理的 initialDelaySeconds 和 periodSeconds。若使用 Docker Swarm,需注意健康检查与滚动更新的配合。
参考资料
延伸阅读
