朕喜技术(ZhenxiJS)
2026.09.02
1 分钟阅读

docker-compose depends_on 不等待服务就绪 —— MySQL 初始化未完成导致 Connection refused

日期:2026-09-02 | 环境:docker-compose + MySQL 8.0 + PyMySQL | 技术栈:Docker Compose, depends_on, healthcheck, service_healthy, mysqladmin, Connection refused

一、问题背景

使用 docker-compose 编排 MySQL + Python 应用时,应用容器在启动后立即尝试连接 MySQL,但 MySQL 还在初始化阶段(建表、创建用户、分配权限),导致应用连接被拒绝。

典型报错:

(2003, "Can't connect to MySQL server on 'mysql' ([Errno 111] Connection refused)")

二、复现步骤

cd scenario/2026-09-02-0000
docker compose up --build

关键日志(depends_on: mysql 没有等待服务就绪):

demo-app  | [✗] 第 1 次尝试连接失败: (2003, "Can't connect to MySQL server on 'mysql' ([Errno 111] Connection refused)")
demo-app  | [✗] 第 3 次尝试连接失败: (2003, "Can't connect to MySQL server on 'mysql' ([Errno 111] Connection refused)")
demo-app  | [✗] 重试 3 次均失败,应用启动失败!

三、根本原因

  1. depends_on 语义限制:depends_on 只等容器进程启动(container started),不检测服务是否就绪(service ready)。
  2. MySQL 初始化耗时:mysql:8.0 首次启动需要初始化数据目录、创建数据库和用户,通常需要数秒到十几秒。
  3. 额外坑:MySQL 8 默认使用 caching_sha2_password 认证,PyMySQL 需要 cryptography 包才能支持该认证方式,否则报 'cryptography' package is required。

四、解决办法

方案:healthcheck + condition: service_healthy

修改 docker-compose.yml:

services:
  mysql:
    # ...原有配置...
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot123"]
      interval: 3s
      timeout: 3s
      retries: 10
      start_period: 5s

  app:
    # ...原有配置...
    depends_on:
      mysql:
        condition: service_healthy

补充:安装 cryptography 包

# requirements.txt
PyMySQL==1.1.0
cryptography>=41.0.0

补充:print 加 flush=True

Docker 容器中 Python 的 print 默认有缓冲,日志不会实时输出,需要加 flush=True 或用 python -u 运行。

五、验证

修复后执行 docker compose up -d --build,输出:

demo-mysql  Waiting
demo-mysql  Healthy
demo-app    Starting

demo-app  | [✓] 第 2 次尝试成功连接 MySQL!
demo-app  | [✓] MySQL 版本: 8.0.46
demo-app  | [✓] 应用初始化完成,开始正常服务...

MySQL 先被标记为 Healthy,app 等 MySQL 健康后才启动并成功连接。

六、经验与避坑

  1. depends_on ≠ 服务就绪:记住"容器起来了"不等于"服务可用了"。在生产环境中,所有依赖外部服务的容器都应该使用 healthcheck + condition: service_healthy。
  2. healthcheck 参数:start_period 很关键,避免 MySQL 初始化期间被误判为 unhealthy;interval 控制检查频率,retries 控制连续失败几次算 unhealthy。
  3. MySQL 8 认证兼容:PyMySQL 连接 MySQL 8 时需要 cryptography,否则报 'cryptography' package is required for sha256_password or caching_sha2_password auth methods。
  4. 应用侧重试仍是好习惯:即使有了 service_healthy,应用侧仍应实现重试逻辑,作为最后一道防线。
  5. 日志要 flush:Docker 容器里调试时,Python print 记得加 flush=True 或直接用 python -u。

可复现命令

# 1. 复现问题(用未修复的版本)
cd scenario/2026-09-02-0000
git stash && docker compose up --build

# 2. 验证修复
git stash pop
docker compose up --build

版权声明

本文为博主原创文章,遵循 CC BY-NC-SA 4.0 许可协议。 转载请注明出处:http://localhost/blogs/2026-09-02-0000-docker-compose-depends-on-healthcheck

分享这篇文章