Docker 容器健康检查异常及 unhealthy 原因排查指南 [复制链接]

一级用户组
金小颖论坛 AI 摘要
AI 正在阅读全文并生成摘要,请稍等……

在日常运维中,经常会遇到这样的情况:容器明明处于 Up 状态,后面却显示 (unhealthy)。这并不矛盾——Up 只说明容器的主进程仍在运行,而 unhealthy 表示 Docker 配置的健康检查命令连续执行失败。健康检查能够发现“进程活着但服务不可用”的问题,例如接口无响应、端口未监听或依赖服务失联。下面将从状态含义、常见原因和排查步骤三个方面,梳理一套可直接执行的诊断方法。🔍

一、理解 Docker 健康状态

镜像或 Compose 服务配置 HEALTHCHECK 后,容器通常会经历 starting、healthy 和 unhealthy 三种健康状态。Docker 会在容器内部周期性执行检查命令,并根据退出码判断结果:退出码 0 表示本次检查成功,1 表示失败,2 为保留值,不建议使用。连续失败次数达到 retries 设置的阈值后,容器就会被标记为 unhealthy。详细规则可参考 Docker HEALTHCHECK 官方说明

需要注意,unhealthy 本身通常不会让普通 Docker 容器自动退出。它主要提供状态标识,是否重启或替换容器,还取决于外部编排平台、监控系统及其恢复策略。

二、先查看具体失败信息

排查时不要急着重启容器,因为重启可能暂时隐藏错误。第一步应确认健康状态及最近几次检查记录:

docker ps
docker inspect --format='{{json .State.Health}}' 容器名

Health.Log 中的 ExitCode、Output、Start 和 End 是关键字段。它们可以帮助判断检查命令是否不存在、请求是否超时、目标端口是否拒绝连接,以及脚本是否因权限问题执行失败。docker inspect 的格式化输出方法可查看 官方命令文档

随后查看应用日志,并留意健康检查失败前后的异常:

docker logs --tail 200 容器名

如果问题偶发,可使用 docker logs -f 持续观察,但应避免只看最后一行就下结论。数据库连接池耗尽、配置加载失败、磁盘只读和内存压力等问题,往往需要结合一段时间内的上下文判断。

三、最常见的 unhealthy 原因

1. 检查工具并不存在

许多健康检查直接调用 curl、wget 或 nc,但精简镜像未必包含这些工具。此时应用本身可能完全正常,检查命令却会返回 command not found。可进入容器验证:

docker exec -it 容器名 sh
command -v curl
command -v wget

解决方法是安装必要工具,或改用镜像已有的运行时编写轻量检查脚本。对于 distroless 一类没有 Shell 的镜像,应使用可直接执行的专用探针程序,而不是依赖 Shell 管道。

2. 地址、端口或路径配置错误

健康检查是在容器内部执行的,因此 localhost 指向当前容器,而不是宿主机或其他服务。若应用监听 8080,检查却请求 80;或者真实路径为 /health,配置写成 /healthz,都会持续失败。进入容器后手动运行完整检查命令,通常能快速暴露此类问题。🌐

3. 应用启动时间超过宽限期

Java 服务、数据库迁移或缓存预热可能需要较长时间。如果 start_period 太短,Docker 会在应用尚未就绪时累计失败次数。此时应根据实际启动过程适当增大 start_period,而不是盲目提高 retries。宽限期应覆盖正常启动波动,但也不宜长到掩盖真正的启动故障。

4. timeout 设置过短

当检查命令执行时间超过 timeout,本次检查会直接被判定失败。服务在高负载下响应稍慢,可能因此在 healthy 与 unhealthy 之间反复切换。可以对检查接口进行实际计时,同时检查 CPU、内存、磁盘 I/O 和网络延迟,再合理调整 timeout。

5. 权限、环境变量或依赖异常

健康检查继承的执行环境可能与人工登录后的环境不同。脚本没有执行权限、相对路径错误、环境变量缺失、DNS 解析失败,以及数据库或消息队列不可达,都可能导致非零退出码。建议使用绝对路径,并以容器实际用户执行检查命令,避免因身份和工作目录差异产生误判。

四、推荐的标准排查顺序

  1. 确认状态:使用 docker ps 判断容器是 unhealthy、restarting,还是主进程已经退出。
  2. 读取检查记录:通过 docker inspect 获取 ExitCode 和 Output,不要只看状态标签。
  3. 检查应用日志:把健康检查时间点与错误日志、资源变化进行对照。
  4. 进入容器复现:使用 docker exec 手动执行完全相同的健康检查命令。
  5. 核对基础条件:确认工具、端口、路径、权限、DNS、证书和环境变量均正确。
  6. 检查参数:结合启动耗时与响应延迟调整 interval、timeout、start_period 和 retries。
  7. 重新构建验证:修改 Dockerfile 或 Compose 配置后重新创建容器,并持续观察多个检查周期。✅

五、健康检查配置建议

  • 检查关键服务能力,而不只是确认某个进程存在。
  • 优先使用专门的 /health 或 /ready 接口,避免请求高开销业务接口。
  • 检查逻辑应快速、稳定,并设置明确的非零失败退出码。
  • 不要把所有外部依赖都塞进同一个探针,否则短暂网络波动可能引发连锁误判。
  • 保持检查频率适中,过于频繁会产生额外资源消耗和日志噪声。
  • 将健康状态接入监控告警,并保留检查输出,便于定位间歇性故障。

总结

Docker 容器显示 unhealthy,核心含义是健康检查命令连续失败,并不必然代表容器主进程已经停止。高效排查的关键,是先查看 Health.Log,再手动复现检查命令,最后依次核对工具、地址、启动时间、超时参数、权限和外部依赖。与其简单重启容器,不如找到失败退出码背后的真实原因,并让健康检查保持轻量、准确和可观测,这样才能真正提升容器服务的稳定性。🛠️

最新回复

请先登录后再回复 登录

uid:2 一级用户组
关注
发帖 1120
评论 0
粉丝 0
关注 0
发新帖
目录
Docker 容器健康检查异常及 unhealthy 原因排查指南