Docker 容器的健康检查 HEALTHCHECK 指令
dockerfile HEALTHCHECK [选项] CMD <命令>
**2. 禁止从基础镜像继承:**
```dockerfile
HEALTHCHECK NONE
如果基础镜像中已经定义了健康检查,而你希望当前镜像取消它,则使用 NONE。
常用选项(均可选,括号内为默认值):
--interval=DURATION:检查间隔,默认30s。--timeout=DURATION:单次检查命令的超时时间,默认30s。--start-period=DURATION:容器启动后等待开始健康检查的时间(此时检查失败不计入重试次数),默认0s。--start-interval=DURATION:在启动期间(start period 内)检查的间隔,用于快速探测,Docker 25.0+ 支持,默认5s。--retries=N:连续失败多少次后状态变为unhealthy,默认3次。
CMD 后面的命令会在容器内部执行,通过退出码报告健康状态:
0:成功 → 容器健康。1:不健康 → 容器运行异常。2:保留值,尽量不使用此退出码(部分旧版本可能会误判)。
注意:健康检查命令不能占用过多资源,执行时长应小于
timeout;应使用轻量级工具(如curl、mysqladmin、自定义脚本)快速探测。
编写你的第一个健康检查
假设我们运行一个 Nginx 服务,希望确认其 Web 服务可用。
FROM nginx:alpine
# 每隔 10 秒使用 curl 检查本地首页,超时 5 秒,启动后等待 30 秒再开始检查
HEALTHCHECK --interval=10s --timeout=5s --start-period=30s --retries=3 \
CMD curl -f http://localhost/ || exit 1
解释:
curl -f:如果服务器返回 HTTP 错误码(如 404、500),-f会让 curl 以非零退出码退出,触发健康失败。|| exit 1:确保非零退出码被捕获,使 Docker 明确收到失败信号。
构建并运行容器后,可通过 docker ps 或 docker inspect 查看健康状态。
docker build -t my-nginx-health .
docker run -d --name web my-nginx-health
docker ps
输出示例:
CONTAINER ID IMAGE ... STATUS
a1b2c3d4e5f6 my-nginx-health ... Up 10 seconds (healthy)
常用健康检查命令示例
针对 Web 应用
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://127.0.0.1:8080/health || exit 1
针对 MySQL 数据库
FROM mysql:8.0
HEALTHCHECK --interval=20s --timeout=5s --retries=3 \
CMD mysqladmin ping -h localhost -u root --password=$MYSQL_ROOT_PASSWORD || exit 1
针对 Redis
FROM redis:alpine
HEALTHCHECK --interval=15s --timeout=3s \
CMD redis-cli ping || exit 1
使用自定义脚本
当某个简单的命令无法满足逻辑时,可以编写 shell 脚本:
COPY healthcheck.sh /usr/local/bin/
RUN chmod +x /usr/local/bin/healthcheck.sh
HEALTHCHECK --interval=30s --timeout=10s CMD /usr/local/bin/healthcheck.sh
healthcheck.sh 内容示例:
#!/bin/sh
# 检查某个关键文件是否存在,并确认进程监听端口
if [ -e /tmp/app.ready ] && netstat -tlnp | grep 3000 > /dev/null; then
exit 0
else
exit 1
fi
查看和管理容器健康状态
1. 使用 docker ps
STATUS 列会显示 (healthy) 或 (unhealthy) 或 (health: starting)(在 start-period 或重试之前)。
2. 使用 docker inspect
获取详细的健康检查日志:
docker inspect --format='{{json .State.Health}}' <container> | jq
返回的 JSON 包含:
Status:"healthy","unhealthy","starting"FailingStreak:当前连续失败次数Log:最近几次检查的详细输出(命令、时间、退出码、输出)
示例日志条目:
"Log": [
{
"Start": "2025-01-01T12:00:00.123456789Z",
"End": "2025-01-01T12:00:00.456789123Z",
"ExitCode": 0,
"Output": "<response from curl...>"
}
]
3. 根据健康状态过滤容器
docker ps --filter "health=healthy"
docker ps --filter "health=unhealthy"
4. 强制触发一次即时健康检查
Docker 不支持手动触发,但你可以使用 docker exec <container> <healthcheck-command> 手动执行相同的命令进行测试。
进阶:启动周期与间隔优化
--start-period 对启动缓慢的应用至关重要(例如 Java 应用、需要预热缓存的数据库)。此期间内,即使检查失败也不会增加失败计数,直到应用真正就绪。例如:
HEALTHCHECK --start-period=60s --start-interval=10s --interval=30s --timeout=5s CMD ...
- 启动前 60 秒内,每 10 秒检查一次(启动间隔)。
- 60 秒后,恢复为每 30 秒一次。
注意:--start-interval 在 Docker 25.0 中引入,旧版本不支持,会报错。请根据 Docker 版本选择使用。
编排中的健康检查行为
Docker Swarm 模式
在服务编排中,当某个副本的健康状态变为 unhealthy 后,Swarm 会自动重启该任务(容器),确保服务的期望副本数始终健康。
docker service create --name my-service --replicas 3 --health-cmd="curl -f http://localhost/" ...
Docker Compose
在 docker-compose.yml 中,通过 healthcheck 字段定义,与 Dockerfile 指令完全对应:
services:
web:
image: my-web
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s