在多容器项目中,应用明明配置了 depends_on,启动时却仍然出现数据库连接失败、缓存拒绝访问或初始化任务尚未完成等问题。🐳 这通常不是配置完全失效,而是把“容器已经启动”误认为“服务已经就绪”。本文从语义、版本、健康检查和运行状态四个方面给出一套可执行的排查方法。
一、理解 depends_on 的真实作用
depends_on 用于描述服务之间的依赖关系,并控制 Compose 创建和停止服务的顺序。例如,API 依赖数据库时,Compose 会先启动数据库容器,再启动 API 容器。但默认条件只要求依赖容器进入运行状态,并不保证数据库已经完成初始化或开始监听端口。
因此,看到数据库容器处于 running,不代表它已经能够接受 SQL 请求。关系型数据库首次创建数据目录、执行初始化脚本或恢复数据时,往往还需要一段准备过程。Docker 官方也明确说明,Compose 默认等待的是容器运行,而不是服务真正可用,具体可参考启动与关闭顺序说明。
二、为什么 condition 看起来失效
1. 使用了短语法
短语法通常写成 depends_on: db 的列表形式,它表达的是启动顺序,效果相当于 service_started。如果业务要求数据库可连接后再启动应用,需要改用长语法,并设置 condition: service_healthy。
2. 依赖服务没有健康检查
service_healthy 必须与依赖服务的 healthcheck 配合使用。如果数据库没有定义健康检查,Compose 就缺少判断“就绪”的依据。健康检查应验证真实服务能力,而不是仅检查进程是否存在。✅
3. Compose 实现或版本不一致
排查时应先执行 docker compose version,确认实际使用的是 Docker Compose 插件,还是旧版 docker-compose 命令。不同历史版本对 Compose 文件格式和条件语法的支持存在差异。如果团队成员和 CI 环境使用的实现不同,就可能出现本地有效、流水线无效的现象。
4. 启动方式绕过了依赖链
直接执行 docker compose run、单独启动某个服务,或使用已经存在的容器时,实际行为可能与完整执行 docker compose up 不同。排查阶段建议先运行 docker compose down,再通过 docker compose up --build 重建整个依赖链。
三、推荐的健康依赖配置
services:
db:
image: postgres:18
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"]
interval: 5s
timeout: 3s
retries: 10
start_period: 20s
api:
build: .
depends_on:
db:
condition: service_healthy
这里的双美元符号用于避免变量被 Compose 提前替换。interval 控制检查间隔,timeout 限制单次检查时长,retries 设置连续失败次数,start_period 则为慢启动服务保留宽限期。参数应结合实际启动特征设置,不宜机械照搬。
对于 Redis,可使用 redis-cli ping;对于 HTTP 服务,可访问专门的健康接口;对于 MySQL,可使用镜像内已有的管理命令。健康检查命令必须存在于容器镜像中,否则会因命令未找到而持续显示不健康。🔍
四、按顺序执行排查
- 运行 docker compose config,检查合并后的最终配置,确认缩进、变量替换和多文件覆盖结果正确。
- 运行 docker compose ps,查看依赖服务是否处于 running、healthy 或 unhealthy 状态。
- 运行 docker inspect 容器名,重点查看 Health、ExitCode 和健康检查输出。
- 运行 docker compose logs db api,按时间对比数据库就绪日志与应用首次连接时间。
- 进入依赖容器手动执行健康检查命令,确认命令路径、用户权限、认证参数和环境变量均正确。
- 从应用容器内访问数据库服务名和容器端口,避免错误地使用 localhost 或映射到宿主机的端口。
五、depends_on 不能替代应用重试
即使启动阶段等待成功,运行期间数据库仍可能重启、网络仍可能短暂抖动。depends_on 主要解决 Compose 管理下的启动和停止顺序,不能持续保证依赖服务永远可用。因此,应用层仍应配置有限次数重试、指数退避、连接超时和连接池重建机制。🛠️
一次性迁移任务可以使用 service_completed_successfully:先等待数据库健康,再执行迁移容器,迁移以零状态码退出后才启动业务服务。需要注意,迁移脚本必须具备幂等性,并在失败时返回非零状态码,否则 Compose 可能把未完成的任务误判为成功。
总结
排查 depends_on 条件失效时,应先区分“容器启动”和“服务就绪”,再核对 Compose 版本、长短语法、健康检查、启动命令及最终配置。可靠方案通常由 depends_on 条件控制、真实健康检查、应用层重试和清晰日志共同组成。按照上述步骤逐层验证,通常可以快速定位问题,并让多服务环境的启动过程更加稳定、可观测和易维护。🚀