Why do I need to configure volumes for running Django and MySQL in Docker containers?

I had a Django project with a MySQL database running on localhost and I wanted to migrate it to Docker containers.
First I migrated the database. I didn’t have any problems and I could connect to it from my Django project perfectly.

However, when I migrated the Django project to another container, I couldn’t connect it to the database. I would always get the following error:

django.db.utils.OperationalError: (2002, "Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2)")

I tried all sorts of solutions and nothing worked.

I was using the following docker-compose configuration:

version: '3.9'
services:
  my-db: 
    build: ./localhost-db
    container_name: my-db
    ports:
      - 3306:3306
    volumes:
      - my-db-vol:/var/lib/mysql

  my-server:
    build: .
    container_name: my-server
    ports:
      - 8000:8000
    command: python3 manage.py runserver 0.0.0.0:8000
    depends_on:
      - my-db

volumes:
  my-db-vol:
    external: true

Then I came across this blog post:
https://dev.to/foadlind/dockerizing-a-django-mysql-project-g4m

Following the configuration in the post, I changed my docker-compose file to:

version: '3.9'
services:
  my-db: 
    build: ./localhost-db
    container_name: my-db
    ports:
      - 3306:3306
    volumes:
      - /tmp/app/mysqld:/var/run/mysqld
      - my-db-vol:/var/lib/mysql

  my-server:
    build: .
    container_name: my-server
    ports:
      - 8000:8000
    command: python3 manage.py runserver 0.0.0.0:8000
    volumes:
      - /tmp/app/mysqld:/run/mysqld
    depends_on:
      - my-db

volumes:
  my-db-vol:
    external: true

Now everything works perfectly, but I can’t figure out why adding /tmp/app/mysqld:/var/run/mysqld to the db volumes and /tmp/app/mysqld:/run/mysqld to the Django volumes solves the problem.

Can anyone explain to me why this configuration is required?

  • 1

    You should configure your application to connect via TCP rather than a Unix socket; my-db:3306.

    – 

  • Btw, you do not need to expose the my-db ports to the outside world to establish a connection from your my-server app as long as you do not need access from outside.

    – 

  • 1

    I bet that you are connecting to MySQL using localhost in your Django app. If that is the case, it wasn’t working because MySQL is not in localhost in the “my-server” container, it is on another container. Now it works because you “fake” it by sharing the running process between the containers. The correct solution is to use “my-db” instead of “localhost” to make the connection. Docker compose will create a hosts entry for each container and they can communicate to each other using this name as long as they are on the same network (as in your case, they all are in the default one).

    – 

Why do I need to configure volumes for running Django and MySQL in Docker containers?

You don’t.

As the error is showing:

django.db.utils.OperationalError: (2002, “Can’t connect to local MySQL server through socket ‘/var/run/mysqld/mysqld.sock’ (2)”)

Once you containerized your app, the MySQL process is not running locally anymore, but in a separate container. You can think of it as a completely separate server.

After your changes it started to work because you are making the my-server container think that MySQL is running locally by “mounting the running process” (not sure what the correct wording would be) to /run/mysqld.

The correct approach would be to change the database connection settings in your Django app to use my-db as the host. This works because Docker Compose set ups the network in a way that containers can communicate to each other using the service name (my-server and my-db in your case).

Leave a Comment