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