Docker 健康检查实战:容器在运行,应用未必能服务
docker ps 显示容器正在运行,只能说明主进程尚未退出,不能证明应用能处理请求。线程卡死、初始化未完成和依赖异常,都可能让进程活着却无法服务。本文示例面向 Docker Engine 25.x 的普通独立容器模式,并按官方 HEALTHCHECK 文档核验;集群调度器如何摘流或替换实例,需要另查所用平台规则。
AI生成概念配图:通过独立探针观察应用响应和检查时机。仅辅助理解,不代表真实界面或实测结果。
先定义健康检查要回答的问题
先说明端点检测的范围:是进程能响应、核心路由可用,还是关键依赖已经准备好。不要把所有外部依赖都塞进一个昂贵探针,否则短暂依赖波动可能让整组实例同时不健康。端点应快速、只读、输出简短,避免创建订单、写入测试数据或进行全表扫描。身份信息和连接密码也不应出现在响应或探针日志里。
下面假设应用在容器内的 8080 端口提供 /healthz,并约定仅 HTTP 200 表示通过。脚本保存为 /usr/local/bin/healthcheck,镜像需要包含 curl,并赋予脚本执行权限。不要因为宿主机安装了 curl,就认为精简容器中一定存在它。
#!/bin/sh
status=$(curl -sS --max-time 2 -o /dev/null \
-w "%{http_code}" http://127.0.0.1:8080/healthz) || exit 1
[ "$status" = 200 ]给探针留出明确的时间边界
docker run -d --name demo-web \ --health-cmd=/usr/local/bin/healthcheck \ --health-interval=30s \ --health-timeout=4s \ --health-start-period=20s \ --health-retries=3 \ demo-web:test
示例镜像名称及参数仅用于测试,运行前需确认资源与镜像来源。探针访问的回环地址属于容器自身,不是宿主机;若应用只监听其他地址,应按实际网络布局调整。curl 自身的超时小于外层健康检查超时,便于脚本先退出;启动宽限期和连续失败次数则应根据真实初始化与短暂波动设定,不能照抄成服务承诺。
配置健康检查后,状态起初为 starting,成功检查可使其变为 healthy,达到规定的连续失败次数后才成为 unhealthy。启动宽限期内的失败有特殊计数规则,而一旦提前成功,后续失败可能开始计数。因此测试既要覆盖慢启动,也要覆盖启动过程中先成功又失败的情形。
从检查记录判断问题发生在哪里
docker inspect --format '{{json .State.Health}}' demo-web
docker exec demo-web /usr/local/bin/healthcheck
printf 'probe_exit=%s\n' "$?"检查最近探针的开始时间、退出码和输出,再在相同容器中执行相同命令。若手动访问宿主机映射端口成功,容器内探针仍失败,二者可能经过不同路径;不要据此直接判定 Docker 出错。还应核对容器用户、文件权限、命令路径和环境变量,避免把探针自身配置错误误报成业务故障。
不健康状态不会自动修好应用
对普通独立容器,健康状态改变本身不会使 Docker 的重启策略自动重启仍在运行的主进程。重启策略主要针对容器退出等条件,不能把 --restart 与 HEALTHCHECK 组合后就当成自动修复系统。若需要告警、摘流或重建,应让相应平台明确消费健康状态,并设置防抖与恢复边界。
验收可在隔离测试环境中让健康端点返回失败,再恢复响应,观察状态转换和事件;不要在生产中随意杀进程或切断依赖。最后核对应用真实入口的访问结果,因为容器内部健康仍可能无法覆盖负载均衡、证书和外部路由。好的探针是可解释的局部信号,而不是“系统一切正常”的保证。


