Docker 容器健康检查机制与实现方法

Docker 健康检查通过 HEALTHCHECK 指令定义容器内进程的存活与就绪状态,是编排平台实现自动重启、滚动更新和流量切换的基础。本文从配置、状态查看到编排场景,逐步拆解健康检查的完整链路。

Docker 容器健康检查机制与实现方法
封面图:ZuCDN · ZuCDN 原创

当容器内的进程仍在运行,但应用已经无法响应请求时,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,需注意健康检查与滚动更新的配合。

参考资料

延伸阅读