Docker化Django应用无法连接本地端口转发的MySQL服务器
解决Docker化Django应用连接MySQL容器的问题
我运行Docker化的Django应用,尝试连接另一Docker容器(端口转发到本地29998)的MySQL服务器,本地已通过MySQL Workbench确认能正常连接。将Django应用设置为network_mode: host后,执行docker-compose build时仍报错:django.db.utils.OperationalError: (2002, "Can't connect to MySQL server on '127.0.0.1' (115)"),目标是让应用成功连接localhost:29998的MySQL服务器。
相关配置
Django应用settings.py
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mytestdb', 'USER': 'userone', 'PASSWORD': 'password', 'HOST': '127.0.0.1', 'PORT': '29998', } }
Django应用docker-compose.yml
version: '3.3' services: mydjangoapp: container_name: mydjangoapp restart: always env_file: .env build: . volumes: - ./apps:/apps - ./core:/core network_mode: host
Django应用Dockerfile
FROM python:3.9 COPY . . # set environment variables ENV PYTHONDONTWRITEBYTECODE 1 ENV PYTHONUNBUFFERED 1 COPY requirements.txt . # install python dependencies RUN pip install --upgrade pip RUN pip install --no-cache-dir -r requirements.txt # running migrations RUN python manage.py migrate # gunicorn CMD ["gunicorn", "--config", "gunicorn-cfg.py", "core.wsgi"]
MySQL容器docker-compose.yml
version: '3.3' services: mysql: image: mysql:latest container_name: mymysqlserver environment: - MYSQL_DATABASE=mytestdb - MYSQL_USER=userone - MYSQL_ROOT_PASSWORD=password - MYSQL_PASSWORD=password ports: - 29998:3306
问题根源
- 网络模式兼容性:
network_mode: host在Linux下容器直接复用宿主机网络,但Windows/macOS中Docker运行在虚拟机内,容器里的127.0.0.1指向虚拟机而非物理宿主机,导致无法连接到宿主机映射的MySQL端口。 - 构建时机问题:Dockerfile中的
RUN python manage.py migrate是在镜像构建阶段执行的,此时MySQL容器可能尚未启动,或者网络连通性未建立,直接触发连接失败。
解决方案
方案一:使用自定义Docker网络(推荐)
通过共享网桥网络让两个容器直接通信,无需端口映射,稳定性更强:
- 修改MySQL的docker-compose.yml,添加自定义网络:
version: '3.3' services: mysql: image: mysql:latest container_name: mymysqlserver environment: - MYSQL_DATABASE=mytestdb - MYSQL_USER=userone - MYSQL_ROOT_PASSWORD=password - MYSQL_PASSWORD=password networks: - app-network networks: app-network: driver: bridge
- 修改Django应用的docker-compose.yml,加入同一网络,并配置依赖关系:
version: '3.3' services: mydjangoapp: container_name: mydjangoapp restart: always env_file: .env build: . volumes: - ./apps:/apps - ./core:/core networks: - app-network depends_on: - mysql # 确保MySQL容器先启动(需额外脚本检测服务就绪) networks: app-network: external: true # 若先启动MySQL的compose,启用此配置;否则删除external,由Django的compose创建网络
- 更新Django的settings.py,用MySQL容器名作为数据库主机:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME': 'mytestdb', 'USER': 'userone', 'PASSWORD': 'password', 'HOST': 'mymysqlserver', # 替换为MySQL容器名 'PORT': '3306', # 使用MySQL默认端口 } }
- 调整Dockerfile,将迁移命令移到启动阶段(避免构建时MySQL未就绪):
CMD ["sh", "-c", "python manage.py migrate && gunicorn --config gunicorn-cfg.py core.wsgi"]
方案二:针对Windows/macOS,修改数据库主机IP
若坚持使用network_mode: host,需找到Docker虚拟机的宿主机IP(通常为192.168.65.2或192.168.99.100),替换settings.py中的127.0.0.1:
DATABASES = { 'default': { # ...其他配置不变 'HOST': '192.168.65.2', # 替换为你的Docker宿主机IP 'PORT': '29998', } }
同时需将Dockerfile中的RUN python manage.py migrate移到启动命令中,确保MySQL已运行。
方案三:Linux系统下调整迁移时机
Linux环境中network_mode: host可直接生效,但仍需将迁移命令从构建阶段移到启动阶段,避免构建时MySQL未启动:
修改Dockerfile的CMD部分为:
CMD ["sh", "-c", "python manage.py migrate && gunicorn --config gunicorn-cfg.py core.wsgi"]
内容的提问来源于stack exchange,提问作者Fletchy
相关产品推荐
相关产品推荐

