Django docker 容器无法连接到 mysql 容器,出现错误“无法连接到 'db' (111) 上的 MySQL 服务器”)

Posted

技术标签:

【中文标题】Django docker 容器无法连接到 mysql 容器,出现错误“无法连接到 \'db\' (111) 上的 MySQL 服务器”)【英文标题】:Django docker container failed to connect to mysql container with error "Can't connect to MySQL server on 'db' (111)")Django docker 容器无法连接到 mysql 容器,出现错误“无法连接到 'db' (111) 上的 MySQL 服务器”) 【发布时间】:2016-11-23 13:17:28 【问题描述】:

我正在尝试使用 docker 设置 Django 开发环境。虽然我可以连接到主机上的 mysql。但是 web 容器无法连接到 mysql 容器并出现以下错误:

django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'db' (111)")

下面是docker配置和django配置:

---------docker-compose.yml---------

version: '2'
services:
  web:
    build: .
  volumes:
    - ".:/code/current"
  ports:
    - "8000:8000"
  depends_on:
    - db
    - redis
  links:
    - db
    - redis
  command: ./manage.py runserver 0.0.0.0:8000

db:
  image: mysql:5.7
  volumes:
    - "./.data/db:/var/lib/mysql"
  environment:
    - MYSQL_ROOT_PASSWORD=root
    - MYSQL_DATABASE=goat_db
  restart: always
  ports:
    - "3306:3306"

redis: 重启:总是 图片:redis:最新 端口: - “6379:6379”

--------------网络镜像的Dockerfile----------

FROM ubuntu:14.04
MAINTAINER Alice
RUN apt-get update
RUN apt-get install -y tar git curl wget emacs build-essential python   python-dev python-distribute python-pip libpcre3 libpcre3-dev libmysqlclient-dev python-m2crypto openssl libssl-dev swig freetds-dev python-pymssql nginx subversion
RUN mkdir -p var/www/goat.garenanow.com/current/log
WORKDIR /var/www/goat.garenanow.com/current
ADD requirements.txt /var/www/goat.garenanow.com/current
RUN pip install -r requirements.txt
ADD . /var/www/goat.garenanow.com/current
EXPOSE 8000

-----django数据库配置---

DATABASES = 
'default': 
    'ENGINE': 'django.db.backends.mysql',
    'NAME': 'goat_db',
    'USER': 'root',
    'PASSWORD': 'root',
    'HOST': 'db',
    'PORT': '3306',
,

【问题讨论】:

【参考方案1】:

对于 db 服务,您的 my.cnf 文件是什么样的?

检查bind-address 值,并确保从网络容器连接的授予权限正确。

要进行测试,您可以将docker exec ... 进入网络容器并尝试从那里连接到db 主机。

【讨论】:

让容器运行一整晚后。它只是工作。(虽然发生了什么????) 不知道 - 有没有可能发生端口冲突并且其他一些服务停止了?还是机器重启了?【参考方案2】:

如果 Django 尝试连接到你的数据库而 MySql 还没有准备好,那么你可能会看到这个错误:

django.db.utils.OperationalError: (2003, "Can't connect to MySQL server on 'db' (111)")

这种情况的解决方案是等待 db server 准备好后再运行 web server。

我们如何做到这一点?

我们创建并运行一个脚本,它会等待数据库服务器准备好,而不是直接运行 Web 服务器。之后,该脚本将运行 Web 服务器。


docker-compose.yml 文件(相关部分是当我们覆盖 web:command 指令并运行脚本而不是立即运行 Web 服务器时)。

version: '3'
services:    
  db:
    restart: always
    image: mysql:5.7
    container_name: my_db
    env_file: env_db
    ports:
      - "3306:3306"

  web:
    restart: always
    build: ./web
    env_file: env_web
    command: ./wait_for_db_and_start_server.sh
    ports:
      - "8000:8000"
    depends_on:
      - db

现在是 env_web 文件(相关部分是START_CMD 变量)。

# Add Environment Variables
DB_NAME=docker
DB_USER=docker_user
DB_PASS=docker_password
DB_SERVICE=db
DB_HOST=db
DB_PORT=3306
START_CMD=python manage.py runserver 0.0.0.0:8000

现在,我们的网络 Dockerfile(相关部分是我们添加 wait_for_db_and_start_server.sh 时)。

FROM python:2.7

ADD wait_for_db_and_start_server.sh .

ADD requirements.txt .
RUN pip install -r requirements.txt

ADD . .

现在 wait_for_db_and_start_server.sh 文件。 (基本上,虽然我们无法在 env_web 文件中定义的指定 $DB_HOST:$DB_PORT 上连接到我们的数据库服务器,但我们等待 3 秒,然后重试 M_LOOPS 次。如果我们能够连接到服务器,然后我们运行在 env_web 文件中定义的$START_CMD。)

#!/bin/sh
# Wait for database to get available

M_LOOPS="10"

#wait for mysql
i=0
# http://***.com/a/19956266/4848859
while ! curl $DB_HOST:$DB_PORT >/dev/null 2>&1 < /dev/null; do
  i=`expr $i + 1`

  if [ $i -ge $M_LOOPS ]; then
    echo "$(date) - $DB_HOST:$DB_PORT still not reachable, giving up"
    exit 1
  fi

  echo "$(date) - waiting for $DB_HOST:$DB_PORT..."
  sleep 3
done

echo "$(date) - $DB_HOST:$DB_PORT Reachable ! - Starting Daemon"
#start the daemon
exec $START_CMD

【讨论】:

你的命令几乎可以工作。我可以从 Web 容器或服务 ping db 容器,但它反复打印 .. ! - Starting Daemon",但它未能进一步执行。【参考方案3】:

如果你想保持你的 web 容器“瘦”,你可能不想添加 mysql 或 postgres 客户端包,只是为了检查你的数据库是否准备好。一些流行的等待脚本有客户端依赖项。

我刚刚创建了一个简单的 Python 脚本,它可以进行本地调用以查看数据库是否正常工作。在这种情况下,我避免添加有效凭据,而只是查找身份验证失败消息。此处的示例适用于 Postgres,但应该很容易适应 MySQL。

wait_for_db.py

import psycopg2.extras
from time import sleep

connect_str = "dbname='postgres' user='nobody' host='db' " + \
              "password='foobar'"

while True:
    try:
        conn = psycopg2.connect(connect_str)
    except psycopg2.OperationalError as e:
        if "authentication failed" in e.args[0]:
            print("Postgres is ready.  Launching site.")
            break
        else:
            print("Waiting for postgres...", e.args[0])
            sleep(1)

然后在你的开发环境 docker-compose.yml 中设置你的 web 容器,这样你就有了类似的东西

command: bash -c "python wait-for-postgres.py; python manage.py runserver 0.0.0.0:8000"

【讨论】:

以上是关于Django docker 容器无法连接到 mysql 容器,出现错误“无法连接到 'db' (111) 上的 MySQL 服务器”)的主要内容,如果未能解决你的问题,请参考以下文章

运行docker django容器时无法连接到服务器

docker-compose 有两个容器:web 无法连接到 db

Django 不会连接到 Redis Docker 容器

Django 无法在 Docker 设置中连接到 Postgres

Docker:Springboot 容器无法连接到 PostgreSql 容器

无法使用 SSH 连接到 docker 容器 [关闭]