Docker容器(Flask+MariaDB)偶发连接失败:无法连接db:3306
问题原因分析与解决方案
核心原因
- 容器启动时序不匹配:Docker Compose的
depends_on仅保证容器启动顺序,无法确保MariaDB服务完全就绪。Flask容器启动时,MariaDB容器虽已启动,但数据库进程可能还在执行初始化(如加载系统表、配置权限),此时发起连接必然被拒绝。 - 重启场景的初始化延迟:停止并删除容器后重新启动,MariaDB需要重新初始化数据库文件(无缓存加持),初始化耗时比首次启动更长,连接失败的概率更高。
具体解决方案
1. 给MariaDB配置健康检查,让Flask等待数据库就绪
修改docker-compose.yml,为db服务添加健康检查规则,同时让app服务仅在db服务健康就绪后启动:
services: db: image: mariadb:latest env_file: .env volumes: - db_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "${MYSQL_USER}", "-p${MYSQL_PASSWORD}"] interval: 5s timeout: 5s retries: 5 app: build: . env_file: .env ports: - "5000:5000" depends_on: db: condition: service_healthy
2. 在Flask代码中添加连接重试逻辑
修改app.py的数据库连接代码,增加重试机制,避免因数据库未就绪导致的一次性连接失败:
import mysql.connector from mysql.connector.errors import InterfaceError import time import os def get_db_connection(): max_retries = 10 retry_delay = 2 # 每次重试间隔2秒 for _ in range(max_retries): try: conn = mysql.connector.connect( host=os.getenv('DB_HOST'), user=os.getenv('DB_USER'), password=os.getenv('DB_PASSWORD'), database=os.getenv('DB_NAME') ) return conn except InterfaceError: time.sleep(retry_delay) raise Exception("无法连接到数据库,重试次数已耗尽")
3. 排查初始化脚本的执行状态
如果有自定义的数据库初始化脚本(挂载到/docker-entrypoint-initdb.d目录),需确认脚本执行完成后数据库服务才会对外提供连接。可在脚本末尾添加mysqladmin ping之类的校验逻辑,确保初始化彻底完成。
额外排查点
- 确认
.env文件中DB_HOST的值为db(即docker-compose中db服务的名称),禁止使用localhost或127.0.0.1 - 查看MariaDB容器日志
docker logs <db容器名>,检查数据库启动过程中是否有初始化错误
内容的提问来源于stack exchange,提问作者elka
相关产品推荐
相关产品推荐

