Are you an LLM? You can read better optimized documentation at /fe/docker/docker-healthcheck.md for this page in Markdown format
Docker 容器健康检查 (Healthcheck) 与自动重启容灾机制深度实战
在生产环境或家庭服务器(Homelab)上,很多人会在 docker-compose.yml 中加上 restart: always 或 restart: unless-stopped,以为这样就能高枕无忧。
但你很可能遇到过这样的尴尬情况:
- 网页打不开了,接口报错
502 Bad Gateway; - 登录服务器一查,
docker ps却显示容器状态是绿色的Up (running); - 只有你手动执行
docker restart <container>之后,服务才恢复正常。
为什么 restart: always 没有生效? 因为 Docker 默认的重启策略只认 “主进程(PID 1)是否退出”。如果你的应用发生了死锁、内存泄露僵死、或者数据库连接池耗尽,进程并没有崩溃,Docker 就会认为它“很健康”而绝不干预。
本文将带你掌握 Docker 原生的 HEALTHCHECK(健康检查探针),并结合 Autoheal 容器实现“假死秒级自愈与有状态依赖启动编排”。
🧭 1. 核心参数详解:如何定义一个健康探针?
在 Dockerfile 或 docker-compose.yml 中,我们可以为容器注入探测命令。
五大核心参数:
test:在容器内定期执行的诊断命令(返回状态码0为健康,1为不健康)。interval:检查间隔时间(例如30s执行一次)。timeout:命令单次执行的超时时间(例如5s内没响应即判定为该次探测失败)。retries:连续失败多少次后,才正式将容器标记为unhealthy(例如连续失败3次)。start_period:启动缓冲期(极其关键!例如有些 Java 或大模型服务冷启动需要 60 秒,在此期间内的检查失败不会计入惩罚重试次数)。
🛠️ 2. 常用基础服务的 Healthcheck 模板库
在编写 Compose 文件时,直接复制以下经过生产验证的探针指令:
1. Web 服务 (Nginx / Node.js / Python API)
yaml
services:
web:
image: nginx:alpine
healthcheck:
test: ['CMD-SHELL', 'wget --no-verbose --tries=1 --spider http://localhost/ || exit 1']
interval: 30s
timeout: 5s
retries: 3
start_period: 10s2. MySQL / MariaDB 数据库
yaml
services:
mysql:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: root_password_123
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-proot_password_123']
interval: 10s
timeout: 5s
retries: 3
start_period: 30s3. PostgreSQL 数据库
yaml
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_USER: myuser
healthcheck:
test: ['CMD-SHELL', 'pg_isready -U myuser']
interval: 10s
timeout: 5s
retries: 3
start_period: 10s4. Redis 缓存服务
yaml
services:
redis:
image: redis:7-alpine
healthcheck:
test: ['CMD', 'redis-cli', 'ping']
interval: 10s
timeout: 3s
retries: 3
start_period: 5s⚡ 3. 进阶依赖编排:让后端等数据库“真正准备好”再启动
在没有健康检查前,Compose 中的 depends_on: [db] 只是指“数据库容器启动了”,但此时数据库内部的数据表还在初始化,后端直接连接就会报错崩溃。
利用健康检查,我们可以实现严格的状态等待:
yaml
services:
backend:
image: my-app:latest
depends_on:
mysql:
condition: service_healthy # 必须等 MySQL 的 healthcheck 变为 healthy 绿灯后,后端才开始启动!
mysql:
image: mysql:8.0
healthcheck:
test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost']
interval: 5s
timeout: 5s
retries: 5🤖 4. 终极自愈方案:联动 Autoheal 实现假死自动重启
原生 Docker 有个非常反直觉的设计:即使容器被标记为 (unhealthy),Docker 也不会主动去重启它!
为了让健康检查真正具备“自愈能力”,我们部署一个轻量的 Autoheal 守护容器:
编写 docker-compose.yml 引入 Autoheal:
yaml
services:
# 自动重启守护者
autoheal:
image: willfarrell/autoheal:latest
container_name: autoheal
restart: always
environment:
- AUTOHEAL_CONTAINER_LABEL=all # 自动监控宿主机所有带 healthcheck 的容器
- AUTOHEAL_INTERVAL=10 # 每 10 秒轮询一次状态
volumes:
- /var/run/docker.sock:/var/run/docker.sock
# 你的业务容器
api_service:
image: my-api:latest
restart: always
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:8080/health']
interval: 20s
timeout: 5s
retries: 3🚀 运行效果:
一旦 api_service 因为死锁或假死连续 3 次探测超时,容器状态变为 unhealthy,Autoheal 容器会在 10 秒内调用 Docker API 强行重启该容器,几秒钟内让业务满血复活!
💬 总结
restart: always只能防“进程暴毙”,HEALTHCHECK + Autoheal才能防“服务假死”。- 在数据库与有状态容器中广泛配置探针,结合
condition: service_healthy,能彻底解决容器启动顺序冲突问题。
延伸阅读推荐:
- 容器数据安全备份:Docker Volume 数据卷备份实操。
- 镜像自动保持最新:Watchtower 容器自动更新配置。
