Files
docker_practice/04_image/dockerfile/healthcheck.md
2026-02-09 09:32:05 -08:00

4.5 KiB
Raw Blame History

HEALTHCHECK 健康检查

基本语法

HEALTHCHECK [选项] CMD <命令>
HEALTHCHECK NONE

HEALTHCHECK 指令告诉 Docker 如何判断容器状态是否正常。这是保障服务高可用的重要机制。


为什么需要 HEALTHCHECK

在没有 HEALTHCHECK 之前Docker 只能通过进程退出码来判断容器状态。

问题场景

  • Web 服务死锁,无法响应请求,但进程仍在运行
  • 数据库正在启动中,尚未准备好接受连接
  • 应用陷入死循环CPU 爆满但进程存活

引入 HEALTHCHECK 后 Docker 定期执行指定的检查命令,根据返回值判断容器是否"健康"。

容器状态转换:
Starting ──成功──> Healthy ──失败N次──> Unhealthy
                    ▲                │
                    └──────成功──────┘

基本用法

Web 服务检查

FROM nginx
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
  CMD curl -fs http://localhost/ || exit 1

命令返回值

  • 0: 成功 (healthy)
  • 1: 失败 (unhealthy)
  • 2: 保留值 (不使用)

常用选项

选项 说明 默认值
--interval 两次检查的间隔 30s
--timeout 检查命令的超时时间 30s
--start-period 启动缓冲期(期间失败不计入次数) 0s
--retries 连续失败多少次标记为 unhealthy 3

屏蔽健康检查

如果基础镜像定义了 HEALTHCHECK但你不想使用它

FROM my-base-image
HEALTHCHECK NONE

常见检查脚本

HTTP 服务

使用 curlwget

## 使用 curl
HEALTHCHECK CMD curl -f http://localhost/ || exit 1

## 使用 wget (Alpine 默认包含)
HEALTHCHECK CMD wget -q --spider http://localhost/ || exit 1

数据库

## MySQL
HEALTHCHECK CMD mysqladmin ping -h localhost || exit 1

## Redis
HEALTHCHECK CMD redis-cli ping || exit 1

自定义脚本

COPY healthcheck.sh /usr/local/bin/
HEALTHCHECK CMD ["healthcheck.sh"]

在 Compose 中使用

可以在 docker-compose.yml 中覆盖或定义健康检查:

services:
  web:
    image: nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 1m30s
      timeout: 10s
      retries: 3
      start_period: 40s

带健康检查的依赖启动:

services:
  web:
    depends_on:
      db:
        condition: service_healthy  # 等待 db 变健康才启动 web
  db:
    image: mysql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]

查看健康状态

## 查看容器状态(包含健康信息)
$ docker ps
CONTAINER ID   STATUS
abc123         Up 1 minute (healthy)
def456         Up 2 minutes (unhealthy)

## 查看详细健康日志
$ docker inspect --format '{{json .State.Health}}' mycontainer | jq
{
  "Status": "healthy",
  "FailingStreak": 0,
  "Log": [
    {
      "Start": "...",
      "End": "...",
      "ExitCode": 0,
      "Output": "..."
    }
  ]
}

最佳实践

1. 避免副作用

健康检查会被频繁执行,不要在检查脚本中进行写操作或消耗大量资源的操作。

2. 使用轻量级工具

优先使用镜像中已有的工具(如 wget),避免为了健康检查安装庞大的依赖(如 curl)。

3. 设置合理的 Start Period

应用启动可能需要时间(如 Java 应用)。设置 --start-period 可以防止在启动阶段因检查失败而误判。

## 给应用 1 分钟启动时间
HEALTHCHECK --start-period=60s CMD curl -f http://localhost/ || exit 1

4. 只检查核心依赖

健康检查应主要关注当前服务是否可用,而不是检查其下游依赖(数据库等)。下游依赖的检查应由应用逻辑处理。


本章小结

要点 说明
作用 检测容器应用是否真实可用
命令 HEALTHCHECK [选项] CMD command
状态 starting, healthy, unhealthy
Compose 支持 condition: service_healthy 依赖
注意 避免副作用,节省资源

延伸阅读