Docker Compose 健康检查实战:让服务按正确顺序启动
Docker Compose 健康检查实战:让服务按正确顺序启动
在本地或测试环境用 Docker Compose 编排多个服务时,很多人会写 depends_on,却发现 API 容器仍然在数据库还没准备好时就启动并报错。原因很简单:默认的 depends_on 只保证容器已经启动,并不保证容器里的服务已经可用。本文用一个 PostgreSQL + Redis + API 的例子,说明如何用 healthcheck 和 condition: service_healthy 解决启动顺序问题。
一、问题复现
假设 API 启动时会立即连接数据库。如果数据库容器刚启动、还在初始化,API 就会得到 connection refused,随后退出。即使加了 restart: always,也会产生无意义的重启和日志噪声。
services:
api:
build: .
depends_on:
- db
这种写法只能保证 db 容器先被创建,不能保证 PostgreSQL 已经接受连接。
二、给依赖服务加健康检查
以 PostgreSQL 为例,使用镜像自带的 pg_isready 做探活:
services:
db:
image: postgres:16-alpine
environment:
POSTGRES_PASSWORD: example
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d postgres"]
interval: 5s
timeout: 3s
retries: 10
start_period: 10s
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
api:
build: .
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
这里几个参数需要理解:
interval:两次探测之间的间隔。timeout:单次探测允许的最长时间。retries:连续失败多少次后判定为 unhealthy。start_period:容器启动后的宽限期,期间失败不计入 retries,适合初始化较慢的服务。
三、验证启动顺序
启动并观察状态:
docker compose up -d
docker compose ps
当 db 和 redis 都变成 healthy 后,api 才会启动。也可以单独查看健康详情:
docker inspect --format '{{json .State.Health}}' <container>
如果 api 仍然启动失败,优先检查应用自身是否有连接重试。健康检查解决的是“容器编排顺序”,不能替代应用内的重试、超时和熔断。
四、几个常见坑
- 镜像里没有
curl或wget。不要在healthcheck里假设工具存在,优先使用服务自带的客户端,例如pg_isready、redis-cli。 - 把
depends_on当成万能依赖。它只影响启动顺序,不会在依赖服务运行中崩溃时自动重启依赖方。 - 健康检查写得太频繁。过于密集的探测会增加容器负担,通常 5 到 10 秒一次已经足够。
- 数据库迁移和健康检查混在一起。迁移应由单独的 init 容器或启动脚本负责,健康检查只负责判断服务是否可连接。
五、小结
Compose 的 healthcheck 配合 depends_on.condition,可以把“容器启动”升级为“服务可用”。它的成本很低,却能显著减少本地开发中的启动失败。建议给数据库、缓存、消息队列等基础设施服务都加上健康检查,并在应用层保留必要的重试逻辑,两者配合才是完整方案。
- 点赞
- 收藏
- 关注作者
评论(0)