11

I'm very new for docker, now I am trying to run django with mariadb in docker through docker-compose, but I always get this error:

I use Docker version 17.09.1-ce, build 19e2cf6, docker-compose version 1.18.0, build 8dd22a9

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

I can connect db correctly after run docker-compose up db in local or remote, and I even can run python manage.py runserver 0.0.0.0:6001 correctly in anaconda virtual environment to connect db service in docker by setting parameters of settings.py file like below:

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',
        }
    }
}

This is my docker-compose.yml file

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

I almost tried everything I can find, but still cannot figure it out, any help would be nice!

What I have tried:

Docker compose mysql connection failing

Linking django and mysql containers using docker-compose

Django connection to postgres by docker-compose

4
  • Where is your MySQL service in docker-compose.yml file? Commented Dec 26, 2017 at 13:27
  • I use mariadb, they are same. Commented Dec 26, 2017 at 13:29
  • Can you provide the url that you use to connect from web to the db. Commented Dec 26, 2017 at 13:31
  • @yamenk What url? Commented Dec 26, 2017 at 13:32

4 Answers 4

18

Finally, I figured it out! The key point is, just as @SangminKim said, I need to use 3306 not 3302 in settings.py, and use db as HOST not 127.0.0.1.

So this is my docker-compose.yml file now:

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

So now we can connect this docker-mysql by mysql -h 127.0.0.1 -P 3302 -u root -p in shell directly, but we have to use db and 3306 in django settings.py file:

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',
        }
    }
}

And we can still check if this port is open, by running extra command in docker-compose.yml file:

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

Here is check_db.py file:

# 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)

By the way, this is my Dockerfile for build django-py35:

FROM python:3.5-alpine
MAINTAINER Xin Xiong "[email protected]"
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

See more details from here: https://github.com/OnlyBelter/django-compose

Sign up to request clarification or add additional context in comments.

Comments

4

You should use the container name instead of localhost (or 127.0.0.1) in your settings.py file. Try providing a container name to the db service in the docker-compose.yml file using container_name attribute and replace the host name in the settings.py by the value of the container_name. (Make sure that they are in the same network that docker compose creates for you.)

3 Comments

I use docker ps to find the running container's name, which is djangopy35_db_1, and changed my settings.py file. But I got same error: django.db.utils.OperationalError: (2003, 'Can\'t connect to MySQL server on \'djangopy35_db_1\' (111 "Connection refused")')
@Belter, You should also change the port to 3306 not 3302 in settings.py.
Yes, you are right! If I use db as HOST, I need to use 3306 as PORT.
1

Build container with this:

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

Make sure MYSQL_ROOT_HOST='%', that means root can connect from any IP.

Comments

1

I have encountered something similar with a django + postgres application and was able to solve it by including this in my settings.py:

DATABASES = { 
        "default": {
         ...
        'HOST': 'host.docker.internal',
        ...

    }
}

It is based on a solution I used years ago: https://stackoverflow.com/a/62147846/7924573

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.