Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

django cannot connect mysql in docker-compose

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

like image 305
Belter Avatar asked Dec 26 '17 13:12

Belter


People also ask

How to set up Django on MySQL in Docker containers?

So without further ado, here are a few quick snippets of code to set up Django on MySQL in Docker containers (using docker compose). build: . ... (whatever else your app requires) ... ... DATABASES = { } ... That should build the images defined in the docker-compose.yml file.

Why do you need docker compose when you have Docker container?

So why do you need docker compose when you have docker container? Generally it is said to be best practices when each docker container runs a process with single responsibility, but for this application you need two containers – one is for Django app and another one is for MySQL server.

How do I install Django on Docker using pip?

This file is used by the RUN pip install -r requirements.txt command in your Dockerfile. Add the required software in the file. Django>=3.0,<4.0 psycopg2-binary>=2.8 Save and close the requirements.txt file.

How do I change the ownership of Django-admin files in Docker?

If you are running Docker on Linux, the files django-admin created are owned by root. This happens because the container runs as the root user. Change the ownership of the new files. $ sudo chown -R $USER:$USER . If you are running Docker on Mac or Windows, you should already have ownership of all files, including those generated by django-admin.


3 Answers

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

like image 153
Belter Avatar answered Oct 19 '22 15:10

Belter


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

like image 22
Janshair Khan Avatar answered Oct 19 '22 15:10

Janshair Khan


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.

like image 34
abd aziz Avatar answered Oct 19 '22 15:10

abd aziz