Docker Compose 健康检查:Running 不代表服务可用
前言
使用 Docker Compose 部署多个服务时,经常会遇到一种情况:容器明明已经启动,应用却仍然连接不上数据库或 Redis,过一会儿重新启动应用又恢复正常。
这类问题有时不是网络故障,而是服务启动顺序和就绪状态没有处理好。
Docker 中的 Running 只能说明容器主进程正在运行,并不代表应用已经准备好接收请求。对于存在依赖关系的服务,可以通过 healthcheck 和 depends_on 改善这一问题。
一、Running 和 Healthy 有什么区别?
先执行:
docker ps
如果容器正常运行,状态通常会显示 Up。
但容器里的应用可能还在初始化,比如数据库正在加载数据、Web 服务正在建立连接。此时虽然主进程已经启动,但业务不一定能正常使用。
Docker 提供了健康检查机制,可以定期在容器内执行指定命令,根据退出状态判断服务是否健康。
常见状态包括:
- starting:健康检查尚未确认服务正常。
- healthy:最近的健康检查成功。
- unhealthy:连续多次健康检查失败。
注意,健康检查只能反映检测条件是否满足,并不能保证应用所有功能都正常。
二、在 Compose 中配置健康检查
以 Redis 为例,可以在 compose.yaml 中添加:
services:
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
start_period: 15s
这里使用 redis-cli ping 检查 Redis 是否能够响应请求。
几个参数分别表示:
- test:实际执行的健康检查命令。
- interval:两次检查的间隔。
- timeout:单次检查允许的最长时间。
- retries:连续失败多少次后判定为 unhealthy。
- start_period:给应用预留初始化时间,此期间的失败通常不计入连续失败次数。
配置完成后,在项目目录执行:
docker compose config
docker compose up -d
docker compose ps
第一条用于检查和查看 Compose 解析后的配置,后两条用于启动服务和查看状态。
如果 Redis 通过健康检查,就可以看到对应的 healthy 状态。
三、depends_on 为什么有时不够用?
假设一个 Web 应用依赖 Redis。
很多人会这样配置:
depends_on:
- redis
这种写法可以控制服务的启动顺序,但默认只要求 Redis 容器已经启动,并不会等待 Redis 完全就绪。
如果 Redis 初始化需要一定时间,Web 应用可能在 Redis 尚未准备好时就尝试连接,导致启动失败。
可以改成:
depends_on:
redis:
condition: service_healthy
配合前面 Redis 服务的 healthcheck,Compose 会等 Redis 通过健康检查后,再启动依赖它的应用。
需要注意,这种方式主要解决启动阶段的依赖就绪问题。如果 Redis 运行一段时间后出现故障,Web 应用仍然需要自己的重连和异常处理机制。
四、健康检查失败会自动重启容器吗?
这是另一个容易混淆的地方。
Docker 的 healthcheck 和 restart policy 并不是一回事。
healthcheck 负责检测并报告容器健康状态;restart policy 则主要根据容器退出等条件决定是否重新启动。
因此,容器显示 unhealthy,并不代表 Docker 一定会自动重启它。
对于长期运行的服务,除了健康检查,还应该结合程序自身的异常处理、日志记录以及必要的监控告警。
不建议为了让服务一直显示 healthy,就把检查条件写得过于宽松。例如只检测进程是否存在,可能无法发现应用已经无法处理请求的情况。
五、如何排查 unhealthy?
首先查看容器:
docker ps -a
如果发现 unhealthy,可以查看健康检查的详细结果:
docker inspect 容器名
重点关注 State.Health 下的 Status、FailingStreak 和 Log。
也可以查看最近的应用日志:
docker logs --tail 100 容器名
常见原因包括:
- 健康检查使用的 curl、wget 等工具没有安装在容器内。
- 检查的端口或路径写错。
- 应用初始化时间过长,超过了允许的失败次数。
- 应用确实出现了连接、配置或资源方面的问题。
尤其要注意,健康检查命令是在容器内部执行的,不能默认容器里拥有宿主机上的所有工具。
六、实际使用建议
不是每个容器都必须设置健康检查,但数据库、缓存和核心 Web 服务通常值得考虑。
如果是 HTTP 服务,可以检查一个能够反映应用就绪状态的接口;如果是 Redis,可以使用 redis-cli ping;数据库则可以结合对应的客户端或就绪检查工具。
检查频率也不需要设置得过高。几秒一次甚至更频繁的检查可能增加不必要的资源开销,具体需要根据应用的启动时间和业务要求调整。
总结
Docker 容器启动成功和服务真正可用,是两个不同的概念。
在 Compose 中,healthcheck 用来判断服务健康状态,depends_on 配合 service_healthy 可以减少依赖服务尚未就绪就启动应用的问题。
不过健康检查并不能代替应用的重试、重连和故障恢复机制。对于长期运行的服务,建议把健康检查、应用日志和监控结合起来使用,而不是只看容器有没有处于 Running 状态。
- 点赞
- 收藏
- 关注作者
评论(0)