You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker化Django+MySQL+Nginx项目时数据库连接失败求助

Django + MySQL + Nginx Docker化连接错误排查

问题描述

执行docker-compose up --build时,Django容器抛出错误:

django.db.utils.OperationalError: (2002, "Can't connect to local server through socket '/run/mysqld/mysqld.sock' (2)")

尝试修改settings.py中数据库HOST为127.0.0.1时,报错:

(2002, "Can't connect to MySQL server on '127.0.0.1' (115)")

改为sqldb(Docker Compose中MySQL服务名)时,报错:

(2002, "Can't connect to MySQL server on 'sqldb' (115)")

现有配置文件

docker-compose.yml

version: '3.7'

services:
  app:
    build: ./app
    env_file:
      - .env
    container_name: app
    restart: always
    expose:
        - 8000
    command: bash -c  "python3 manage.py collectstatic --noinput && python3 manage.py migrate --noinput --fake-initial && \
              gunicorn -b 0.0.0.0:8000 veblog.wsgi"
    environment:
      - MYSQL_DATABASE=${NAME}
      - MYSQL_USER=${USER_NAME}
      - MYSQL_PASSWORD=${PASSWORD}
      - MYSQL_HOST=sqldb
    mem_limit: 1g
    depends_on:
      - sqldb
      # - nginx
    volumes:
      - ./volumes/app:/app
      - type: bind
        source: ./volumes/media
        target: /app/media
      - type: bind
        source:  ./volumes/static
        target:  /app/static
    
  
  nginx:
      build: ./nginx
      container_name: nginx
      restart: always
      ports:
        - 8000:80
  
     
  sqldb:
    image:  mysql:latest
    container_name: sqldb
    restart:  always
    depends_on:
      - nginx
    expose:
      - 3306
    environment:
      - MYSQL_DATABASE=${NAME}
      - MYSQL_USER=${USER_NAME}
      - MYSQL_PASSWORD=${PASSWORD}
      - MYSQL_ROOT_PASSWORD=${ROOT_PASSWORD} 
      - MYSQL_INITDB_SKIP_TZINFO=true  
      - MYSQL_INIT_COMMAND=SET GLOBAL host_cache_size=0;
    volumes:
      - type:  bind
        source:  ./volumes/dbdata
        target:  /var/lib/mysql
      - /usr/share/zoneinfo:/usr/share/zoneinfo:ro

app/Dockerfile

FROM python:3
ENV PYTHONDONTWRITEBYCODE 1
ENV PYTHONUNBUFFERED 1
RUN mkdir -p /app
WORKDIR /app
COPY . .
RUN apt update
RUN apt install gcc python3-dev musl-dev -y
RUN pip install --upgrade pip
RUN pip install mysqlclient
COPY ./requirement.txt .
RUN pip install -r requirement.txt
ADD . /app/
RUN pip install gunicorn

nginx/Dockerfile

FROM nginx:alpine
RUN rm /etc/nginx/conf.d/default.conf
ADD default.conf /etc/nginx/conf.d/default.conf

nginx/default.conf

upstream app {
    server app:8000;
}

server {
    listen 80;
    server_name localhost;
    location / {
        proxy_pass http://app;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }
    location /media/ {
        alias /app/media;
    }
    location /static/ {
        alias /app/static;
    }
}

Django settings.py 数据库配置

'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': config('NAME'),
        'USER': config('USER_NAME'),
        'PASSWORD': config('PASSWORD'),
        'HOST': 'localhost',  # host.docker.internal
        'PORT': '3306',
}

已尝试的无效操作

  • 调整本地MySQL权限:sudo chmod -R 755 /var/run/mysqld
  • 创建socket软链接:ln -s /var/lib/mysql/mysql.sock /var/run/mysqld/mysqld.sock
  • 卸载重装本地MySQL
  • 在MySQL配置文件中设置bind-address=0.0.0.0(但执行SHOW VARIABLES LIKE 'bind-address'返回空集合)
  • 开放防火墙权限
  • 单独执行docker build构建镜像

解决方案

1. 修正数据库连接目标

Docker Compose中服务通过服务名通信,Django应连接容器化的MySQL服务而非本地MySQL。修改settings.py的数据库配置:

'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': config('NAME'),
        'USER': config('USER_NAME'),
        'PASSWORD': config('PASSWORD'),
        'HOST': 'sqldb',  # 改为Docker Compose中的MySQL服务名
        'PORT': '3306',
}

2. 修复服务依赖顺序

当前sqldb依赖nginx的逻辑错误,会导致MySQL启动延迟,Django可能在MySQL就绪前发起连接。调整docker-compose.yml的依赖关系:

  • 移除sqldb中的depends_on: - nginx
  • 让nginx依赖app(Nginx需反向代理已启动的Django服务)
    修改后的关键片段:
services:
  app:
    # 其他配置不变
    depends_on:
      - sqldb
  
  nginx:
      # 其他配置不变
      depends_on:
        - app
  
  sqldb:
    # 其他配置不变
    # 移除depends_on: - nginx

3. 确保MySQL就绪后启动Django

depends_on仅保证启动顺序,不确保服务完全就绪。给Django添加等待MySQL就绪的逻辑:

  1. 在app目录下添加wait-for-it.sh脚本(功能为等待指定端口服务就绪)
  2. 修改app/Dockerfile添加脚本权限:
# 其他配置不变
COPY wait-for-it.sh /app/
RUN chmod +x /app/wait-for-it.sh
  1. 更新docker-compose.yml中app的启动命令:
command: bash -c "./wait-for-it.sh sqldb:3306 -- python3 manage.py collectstatic --noinput && python3 manage.py migrate --noinput --fake-initial && gunicorn -b 0.0.0.0:8000 veblog.wsgi"

4. 排查本地MySQL冲突

若本地MySQL占用3306端口,可能干扰Docker内部通信,建议暂时停止本地MySQL测试:

sudo systemctl stop mysql

5. 验证MySQL容器状态

启动后查看MySQL容器日志,确认服务正常就绪:

docker logs sqldb

日志中出现ready for connections即为正常状态。


内容的提问来源于stack exchange,提问作者zahra hemmati

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 11:43:15