【问题标题】:django cannot connect mysql in docker-composedjango 无法在 docker-compose 中连接 mysql
【发布时间】:2018-06-07 08:04:45
【问题描述】:

我对docker很陌生,现在我正在尝试通过docker-compose在docker中使用mariadb运行django,但我总是收到这个错误:

我使用Docker version 17.09.1-ce, build 19e2cf6docker-compose version 1.18.0, build 8dd22a9

django.db.utils.OperationalError: (2003, 'Can\'t connect to MySQL \'mariadb55\' 上的服务器 (111 "Connection denied")')

我可以在本地或远程运行docker-compose up db后正确连接db,我什至可以在anaconda虚拟环境中正确运行python manage.py runserver 0.0.0.0:6001通过设置参数来连接docker中的db服务settings.py 文件如下:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'test',
        'USER': 'belter',
        # 'HOST': 'mariadb55',
        'HOST': '127.0.0.1',
        'PORT': '3302',
        'PASSWORD': 'belter_2017',
        'default-character-set': 'utf8',
        'OPTIONS': {
            'sql_mode': 'traditional',
        }
    }
}

这是我的 docker-compose.yml 文件

version: '3'

services:
  db:
    image: mariadb:5.5
    restart: always
    environment:
      - MYSQL_HOST=localhost
      - MYSQL_PORT=3306
      - MYSQL_ROOT_HOST=%
      - MYSQL_DATABASE=test
      - MYSQL_USER=belter
      - MYSQL_PASSWORD=belter_2017
      - MYSQL_ROOT_PASSWORD=123456_abc
    volumes:
      - /home/belter/mdbdata/mdb55:/var/lib/mysql
    ports:
      - "3302:3306"
  web:
    image: onlybelter/django_py35
    command: python3 manage.py runserver 0.0.0.0:6001
    volumes:
      - /mnt/data/www/mysite:/djcode
    ports:
      - "6001:6001"
    depends_on:
      - db
    links:
      - db:mariadb55

我几乎尝试了所有我能找到的东西,但仍然无法弄清楚,任何帮助都会很好!

我尝试过的:

Docker compose mysql connection failing

Linking django and mysql containers using docker-compose

Django connection to postgres by docker-compose

【问题讨论】:

  • docker-compose.yml 文件中的 MySQL 服务在哪里?
  • 我用mariadb,它们是一样的。
  • 您能否提供用于从 Web 连接到数据库的 url。
  • @yamenk 什么网址?

标签: mysql django docker docker-compose mariadb


【解决方案1】:

用这个构建容器:

docker run --name mysql-latest  \
-p 3306:3306 -p 33060:33060  \
-e MYSQL_ROOT_HOST='%' -e MYSQL_ROOT_PASSWORD='strongpassword'   \
-d mysql/mysql-server:latest

确保MYSQL_ROOT_HOST='%',这意味着root可以从任何IP连接。

【讨论】:

    【解决方案2】:

    我终于明白了! 关键是,正如@SangminKi​​m 所说,我需要在settings.py 中使用3306 而不是3302,并使用db 作为HOST 而不是127.0.0.1

    这是我现在的 docker-compose.yml 文件:

    version: '3'
    
    services:
      db:
        image: mariadb:5.5
        restart: always
        environment:
          - MYSQL_HOST=localhost
          - MYSQL_PORT=3306  # cannot change this port to other number
          - MYSQL_ROOT_HOST=%
          - MYSQL_DATABASE=test
          - MYSQL_USER=belter
          - MYSQL_PASSWORD=belter_2017
          - MYSQL_ROOT_PASSWORD=123456_abc
        volumes:
          - /home/belter/mdbdata/mdb55:/var/lib/mysql
        ports:
          - "3302:3306"
      web:
        image: onlybelter/django_py35
        command: python3 manage.py runserver 0.0.0.0:6001
        volumes:
          - .:/djcode
        ports:
          - "6001:6001"
        depends_on:
          - db
    

    所以现在我们可以通过mysql -h 127.0.0.1 -P 3302 -u root -p在shell中直接连接这个docker-mysql,但是我们必须在djangosettings.py文件中使用db3306

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'test',
            'USER': 'belter',
            # 'HOST': 'mariadb55',
            'HOST': 'db',  #<---
            'PORT': '3306',   #<---
            'PASSWORD': 'belter_2017',
            'default-character-set': 'utf8',
            'OPTIONS': {
                'sql_mode': 'traditional',
            }
        }
    }
    

    我们仍然可以通过在docker-compose.yml 文件中运行额外的命令来检查此端口是否打开:

    ...
      web:
        image: onlybelter/django_py35
        command: /bin/sh -c "python check_db.py --service-name mysql --ip db --port 3306"
        volumes:
          - .:/djcode
    ...
    

    这是 check_db.py 文件:

    # check_db.py 
    
    import socket
    import time
    import argparse
    """ Check if port is open, avoid docker-compose race condition """
    
    parser = argparse.ArgumentParser(description='Check if port is open, avoid\
                                     docker-compose race condition')
    parser.add_argument('--service-name', required=True)
    parser.add_argument('--ip', required=True)
    parser.add_argument('--port', required=True)
    
    args = parser.parse_args()
    
    # Get arguments
    service_name = str(args.service_name)
    port = int(args.port)
    ip = str(args.ip)
    
    # Infinite loop
    while True:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        result = sock.connect_ex((ip, port))
        if result == 0:
            print("{0} port is open! Bye!".format(service_name))
            break
        else:
            print("{0} port is not open! I'll check it soon!".format(service_name))
            time.sleep(3)
    

    顺便说一句,这是我的 Dockerfile 用于构建django-py35

    FROM python:3.5-alpine
    MAINTAINER Xin Xiong "xiongxin20008@126.com"
    ENV PYTHONUNBUFFERED 1
    RUN set -e; \
            apk add --no-cache --virtual .build-deps \
                    gcc \
                    libc-dev \
                    linux-headers \
                    mariadb-dev \
                    python3-dev \
                    postgresql-dev \
                    freetype-dev \
                    libpng-dev \
                    g++ \
            ;
    RUN mkdir /djcode
    WORKDIR /djcode
    ENV REFRESHED_AT 2017-12-25
    ADD requirements.txt /djcode/
    RUN pip install --no-cache-dir -r /djcode/requirements.txt
    RUN pip install uwsgi
    ADD . /djcode/  # copy . to /djcode/
    EXPOSE 6001
    

    从这里查看更多详细信息:https://github.com/OnlyBelter/django-compose

    【讨论】:

      【解决方案3】:

      您应该在 settings.py 文件中使用容器名称而不是 localhost(或 127.0.0.1)。尝试使用container_name 属性为docker-compose.yml 文件中的db 服务提供容器名称,并将settings.py 中的主机名替换为container_name 的值。 (确保它们位于 docker compose 为您创建的同一网络中。)

      【讨论】:

      • 我使用docker ps 查找正在运行的容器的名称,即djangopy35_db_1,并更改了我的settings.py 文件。但我得到了同样的错误:django.db.utils.OperationalError: (2003, 'Can\'t connect to MySQL server on \'djangopy35_db_1\' (111 "Connection refused")')
      • @Belter,您还应该在settings.py 中将端口更改为3306 而不是3302
      • 是的,你是对的!如果我使用db 作为HOST,我需要使用3306 作为PORT
      猜你喜欢
      • 1970-01-01
      • 2021-06-16
      • 2017-07-05
      • 2020-02-12
      • 1970-01-01
      • 2019-07-07
      • 2020-06-04
      相关资源
      最近更新 更多