mysqldjangodockercontainers

Django will not connect to mysql container on port 3307 with 3307:3306 mapped in docker compose file


docker-compose.yaml

services:
  db:
    image: mysql:9.0.1
    container_name: db_mysql_container
    environment:
      MYSQL_DATABASE: backend
      MYSQL_USER: asdf
      MYSQL_PASSWORD: asdf
      MYSQL_ROOT_PASSWORD: asdf
    ports:
      - '3307:3306'
  api:
    build: .
    container_name: django_container
    command: bash -c "pip install -q -r requirements.txt &&
      python manage.py migrate &&
      python manage.py runserver 0.0.0.0:8000"
    volumes:
      - .:/app
    ports:
      - '8000:8000'
    depends_on:
      - db

django settings

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': "backend",
        'USER': "asdf",
        'PASSWORD': "asdf",
        'HOST': "db",
        'PORT': "3307",
    }
}

The rest of my django settings file is what the default is. The whole django project is just what you start out with from the django-admin startproject command, plus the mysqlclient dependency.

Here is my Dockerfile, nothing special going on:

# Use an official Python runtime as a parent image
FROM python:3.12

# Set environment variables
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# Set the working directory
WORKDIR /app

# Install dependencies
COPY requirements.txt /app/

# Copy the project code into the container
COPY . /app/

requirements.txt:

asgiref==3.8.1
Django==5.1
mysqlclient==2.2.4
sqlparse==0.5.1

When I bring up the db, wait, and then bring up the api, I get this:

django.db.utils.OperationalError: (2002, "Can't connect to server on 'db' (115)")

If I change my docker-compose.yaml to this:

services:
  db:
    image: mysql:9.0.1
    container_name: db_mysql_container
    environment:
      MYSQL_DATABASE: backend
      MYSQL_USER: asdf
      MYSQL_PASSWORD: asdf
      MYSQL_ROOT_PASSWORD: asdf
      MYSQL_TCP_PORT: 3307
    ports:
      - '3307:3307'
  api:
    build: .
    container_name: django_container
    command: bash -c "pip install -q -r requirements.txt &&
      python manage.py migrate &&
      python manage.py runserver 0.0.0.0:8000"
    volumes:
      - .:/app
    ports:
      - '8000:8000'
    depends_on:
      - db

it works. It seems like I should be able to run mysql in the container on port 3306 and then have docker send traffic sent to my host 3307 port to the container's 3306 port.


Solution

  • Your containers communicate directly to each other over the docker internal network on their "inside" ports. When you do a port exposure like "outside:inside" the outside port is only relevant to traffic targeting the host system. Your containers do not use the host ports to talk to each other.

    That's why the 3707:3707 mapping works when the application is configured to connect using port 3707 -- because the inside port is using port 3707.

    In the first example with 3707:3706, you would need to configure the application to connect on port 3706, since that's the inside port.