如何解决FastAPI容器无法连接MySQL容器的2003(HY000)错误
FastAPI容器无法连接MySQL容器(仅初始化创建DB时失败)
近期尝试将FastAPI Python服务器Docker化并部署多实例。单独运行MySQL容器时一切正常,但将Web服务器封装为容器后,始终无法连接到MySQL服务器,导致应用无法正常运行。
更新1:经排查发现,若数据库已提前创建,应用可以正常发送请求并获取响应,仅在通过代码中的初始化脚本创建数据库时会出现连接失败问题。
应用数据库连接代码片段
from fastapi import FastAPI import mysql.connector app = FastAPI() dbconfig = { "host": "localhost", "database": "server_db", "user": "db_user", "password": "user-password" } # Checking DB connection try: init_cnx = mysql.connector.connect( host='localhost', user='db_user', password='user-password' ) cursor = init_cnx.cursor() cursor.execute("SHOW DATABASES LIKE 'server_db'") if cursor.fetchone() == None: # Create DB in case one doesn't exist cursor.execute("CREATE DATABASE server_db") cursor.execute("USE server_db") cursor.execute("CREATE TABLE Messages (" "message_id INT NOT NULL AUTO_INCREMENT," "sender_name VARCHAR(32)," "message_text VARCHAR(64)," "created_at DATE," "user_messages_count INT," "PRIMARY KEY (message_id));") print('DB Created!') cursor.close() init_cnx.close() except mysql.connector.Error as err: print("On init_cnx:", err) # DB I/O function async def execute_db_query(query, cursor_buffered=False): cnx = mysql.connector.connect(**dbconfig) try: cursor = cnx.cursor(buffered=cursor_buffered) cursor.execute("USE server_db") cursor.execute(query) result = cursor.fetchall() cnx.commit() print("Query executed successfully!") return result except Exception as e: print("Error executing query:", e) finally: if cnx: cnx.close() # Get root function, just to check if app is connected to DB @app.get("/") async def get_root(): try: entries_count = await execute_db_query("SELECT COUNT(*) FROM Messages", cursor_buffered=True) return {"Messages entries": entries_count[0][0]} except Exception as e: return {"Error": e}
服务器Dockerfile
FROM python:3.11.4-slim-bookworm WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY server.py . EXPOSE 8000 CMD ["uvicorn", "server:app", "--host", "0.0.0.0", "--port", "8000"]
init.sql脚本
CREATE USER 'db_user'@'%' IDENTIFIED BY 'user-password'; GRANT ALL PRIVILEGES ON *.* TO 'db_user'@'%' WITH GRANT OPTION; FLUSH PRIVILEGES;
docker-compose.yml配置
version: "3.8" services: db_mysql: image: mysql:8 restart: always environment: MYSQL_ROOT_PASSWORD: "root" volumes: - "./mysql/init.sql:/docker-entrypoint-initdb.d/init.sql" - "./mysql/db_mysql_data:/var/lib/mysql" - "./mysql/mysql_logs:/var/log/mysql" networks: - dummy_network server_1: image: dummy_msg_server ports: - "8081:8000" networks: - dummy_network #command: sh -c "sleep 60s" depends_on: - db_mysql server_2: image: dummy_msg_server ports: - "8082:8000" networks: - dummy_network #command: sh -c "sleep 60s" depends_on: - db_mysql volumes: db_mysql_data: #external: true networks: dummy_network: driver: bridge
已排查情况
- 确认MySQL容器完全就绪后才尝试连接,排除初始化未完成问题
- 尝试过使用主机名/IP地址连接、更换Python基础镜像、显式配置共享网络
- 曾配置MySQL端口映射3306:3306,非问题根源
解决方案
核心问题定位
代码中**初始化连接的硬编码localhost**是关键问题:在Docker容器内,localhost指向容器自身,而非MySQL容器。更新1中提到"DB提前创建后可正常运行",说明后续查询用的dbconfig可能已修正,但初始化段仍用localhost,导致创建DB时连接失败。
修复步骤
统一数据库连接地址
将初始化代码的硬编码localhost改为Docker Compose中MySQL服务的名称db_mysql,并复用dbconfig配置避免重复:dbconfig = { "host": "db_mysql", # 替换localhost为MySQL服务名 "database": "server_db", "user": "db_user", "password": "user-password" } # 修改初始化连接逻辑 init_cnx = mysql.connector.connect( host=dbconfig["host"], user=dbconfig["user"], password=dbconfig["password"] )Docker的内置DNS会自动将服务名
db_mysql解析为对应容器的IP,确保网络互通。优化初始化逻辑(可选,推荐)
将创建数据库和表的逻辑移到init.sql中,由MySQL容器自动执行,避免在应用代码中处理初始化:CREATE USER 'db_user'@'%' IDENTIFIED BY 'user-password'; GRANT ALL PRIVILEGES ON *.* TO 'db_user'@'%' WITH GRANT OPTION; -- 新增DB和表初始化 CREATE DATABASE IF NOT EXISTS server_db; USE server_db; CREATE TABLE IF NOT EXISTS Messages ( message_id INT NOT NULL AUTO_INCREMENT, sender_name VARCHAR(32), message_text VARCHAR(64), created_at DATE, user_messages_count INT, PRIMARY KEY (message_id) ); FLUSH PRIVILEGES;之后可删除应用代码中创建DB和表的逻辑,简化代码结构。
用环境变量传递配置(可选)
在docker-compose.yml中为Web服务添加环境变量,避免代码硬编码:server_1: image: dummy_msg_server ports: - "8081:8000" networks: - dummy_network environment: DB_HOST: db_mysql DB_USER: db_user DB_PASSWORD: user-password DB_NAME: server_db depends_on: - db_mysql应用代码读取环境变量:
import os dbconfig = { "host": os.getenv("DB_HOST", "db_mysql"), "database": os.getenv("DB_NAME", "server_db"), "user": os.getenv("DB_USER", "db_user"), "password": os.getenv("DB_PASSWORD", "user-password") }
内容的提问来源于stack exchange,提问作者ngumbk
相关产品推荐
相关产品推荐

