朕喜技术(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 次均失败,应用启动失败!
三、根本原因
depends_on语义限制:depends_on只等容器进程启动(container started),不检测服务是否就绪(service ready)。- MySQL 初始化耗时:mysql:8.0 首次启动需要初始化数据目录、创建数据库和用户,通常需要数秒到十几秒。
- 额外坑: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 健康后才启动并成功连接。
六、经验与避坑
depends_on≠ 服务就绪:记住"容器起来了"不等于"服务可用了"。在生产环境中,所有依赖外部服务的容器都应该使用healthcheck + condition: service_healthy。- healthcheck 参数:
start_period很关键,避免 MySQL 初始化期间被误判为 unhealthy;interval控制检查频率,retries控制连续失败几次算 unhealthy。 - MySQL 8 认证兼容:PyMySQL 连接 MySQL 8 时需要
cryptography,否则报'cryptography' package is required for sha256_password or caching_sha2_password auth methods。 - 应用侧重试仍是好习惯:即使有了 service_healthy,应用侧仍应实现重试逻辑,作为最后一道防线。
- 日志要 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
