Dockerizing Django and MySql
Tags: django, python, mysql, docker
Published: 2022-12-21 08:55:32

## Dockerizing Django and MySql(Linux)
In this guide, I will show you how to dockerize your django project in one container and MySql Server in another container in Linux Operating System. We will create, manage and run these container using docker-compose. For this I assume you have installed python, docker and docker-compose in your machine. If not, refer to ["install python"](https://www.python.org/downloads/) and ["install docker"](https://docs.docker.com/get-docker/).
## First we setup our django project using terminal:

```
$ mkdir myProject
$ cd myProject
$ python -m venv venv
$ source venv/bin/activate
(venv) $ pip install Django==4.1.4 python-dotenv
(venv) $ django-admin startproject core .
(venv) $ pip freeze > requirements.txt
```
Lets go line by line:

- `mkdir myProject` create a new directory in your current working directory
- `cd myProject` change directory to myProject
- `python -m venv venv` create a python virtual environment
- `source venv/bin/activate` activate the virtual environment.
- `pip install Django==4.1.4 python-dotenv` install django and python-dotenv package. Python-dotenv package is used for securing our secret keys
- `django-admin startproject core .` create django project in current directory. The dot after core represents the current directory
- `pip freeze > requirements.txt` create a requirements.txt file in current directory with all the package installed in this virtual environment

## This is my basic project directory tree:

![Basic Project Folder Tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2a1ufrhdukz1e5rk87vy.png)


## Configuring Our Project:
- Create a .env file in our project directory with touch .env
- Setup our python-dotenv in settings.py of myProject/core/settings.py

```
import os
from dotenv import load_dotenv
load_dotenv(os.path.join(BASE_DIR, ".env"))
```

![settings](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rvev1zrph0uaeo18u179.png)


- Create a new secret key for our project
```
(venv) $ python manage.py shell
>>> from django.core.management.utils import get_random_secret_key
>>> print(get_random_secret_key())
>>> exit()
```
- Copy the secret key and paste it to .env file
- Replace the secret key in settings.pyby pointing it to the .env file

```
SECRET_KEY = str(os.getenv("DJANGO_SECRET_KEY"))
```
- Configure Django Database in settings.py

```
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': str(os.getenv("DATABASE_NAME")),
        'USER': str(os.getenv("DATABASE_USER")),
        'PASSWORD': str(os.getenv("DATABASE_PASSWORD")),
        'HOST': str(os.getenv("DATABASE_HOST")),
        'PORT': 3306,
    }
}
```
- Configure .env for database

```
DATABASE_NAME = "mysql_new_db"
DATABASE_USER = "myProject"
DATABASE_PASSWORD = "myProject"
DATABASE_ROOT_PASSWORD = "myProject"
DATABASE_HOST = "db"
```
- Setup files for dockerizing our project and MySql:
We need to create three files to dockerizing our project and MySql. They are .dockerignore, Dockerfile and docker-compose.yml. A Dockerfile contains all the commands a user could call on the command line to assemble an image. .dockerignore is similar to .gitignore. It allows to specify the list of files and folders to ignore when building a image. And docker-compose.yml a YAML file to define the services and we can also spin everything up or tear it all down.

## Setup Dockerfile
Create a Dockerfile in project directory (venv) $ touch Dockerfile

```
FROM python:3
LABEL maintainer="ishanshrestha"
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED 1 
WORKDIR /app
COPY requirements.txt /app/
RUN pip install --upgrade pip
RUN pip install -r requirements.txt
COPY . /app/
EXPOSE 8000
```
- `FROM python:3` is the python docker image. It will be your base image your Docker image will be built upon.
- `LABEL maintainer="ishanshrestha"` specifies the maintainer of your docker image. A maintainer can be your name or the website you own. It is a best practice to define a maintainer.
- `ENV PYTHONDONTWRITEBYTECODE=1` prevents Python from writing out files with extension .pyc .
- `ENV PYTHONUNBUFFERED` 1 tells Python that you don't want to buffer the stdin/stdout. Prints output directly to the console, which prevents any delay of message on the screen.
- `WORKDIR /app` is a default directory in your docker image where the all docker commands runs from.
- `COPY requirements.txt /app/` copies earlier created requirements.txt to the docker image working directory.
- `RUN pip3 install  -- upgrade pip` upgrade the pip in the docker image.
- `RUN pip install -r requirements.txt` installs all the packages defined in the requirements.txt file.
- `COPY . /app/` copies our project to working directory of your docker image.
- `EXPOSE 8000` exposes the container to your local machine

## Setup docker-compose.yml
Create a docker-compose file in project directory (venv) $ touch docker-compose.yml

```
version: "3.9"

services:
  db:
    container_name: mysql_new_db
    image: mysql:latest
    restart: always
    ports:
      - 3306:3306
    environment:
      - MYSQL_DATABASE=${DATABASE_NAME}
      - MYSQL_USER=${DATABASE_USER}
      - MYSQL_PASSWORD=${DATABASE_PASSWORD}
      - MYSQL_ROOT_PASSWORD=${DATABASE_ROOT_PASSWORD}
      - MYSQL_HOST=${DATABASE_HOST}
    volumes:
      - .:/app
      - mysql_new_data:/var/lib/mysql

  app:
    container_name: app
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/app
    ports:
      - 8000:8000
    depends_on:
      - db
    restart: always

volumes:
  mysql_new_data:
```
- We define two services int the docker-compose file. These services db and app are the two containers we are going to create. "db" refers to our MySql container and "app" refers to our project container.
### Lets break our "db" section:
- `container_name: mysql_new_db` is the name of the container
- `image: mysql:latest` is the MySql docker image that we pull from docker hub
- `restart: always` sets the restart policy of Docker container to
- `port: 3306:3306` defines the port for our MySql Server
- `environment:` defines the environment variables for MySql Server
- `volumes:` defines volume mapping of database storage

### Now, lets break our "app" section:
- `build: .` points to project directory when building the image
- `command:` runs our django projects
- `ports:` exposes our project image to the local machine
- `depends_on:` sets the order of image for start/stop. In our case, MySql container/image must start before our app image/container.

## Setup dokcerignore
.

```
git
.gitignore

.docker
code/__pycache__/
code/*/__pycache__/
code/*/*/__pycache__/
code/*/*/*/__pycache__/
.env/
.venv/
venv
```
## Final myProject directory tree:

![Final Project Tree](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jvreop9uo0d1z34gji8c.png)

## Final project directory treeAppend mysqlclient==2.1.1 to requirements.txt
## Build and run the docker container
- To build and run the docker continer:

```
(venv) $ docker-compose up -d --build
```
- It will take some time to build the image for first time. It uses caching system to speed up the image building for second time.
- In command -d tag tells docker to run in the background. To stop the conatiner, run the command 

```
docker-compose down
```

- View the container running

```
$ docker ps
CONTAINER ID   IMAGE           COMMAND                  CREATED         STATUS         PORTS                                                  NAMES
2303bef6e116   myproject-app   "python manage.py ru…"   5 minutes ago   Up 5 minutes   0.0.0.0:8000->8000/tcp, :::8000->8000/tcp              app
b2ea4a7ba174   mysql:latest    "docker-entrypoint.s…"   5 minutes ago   Up 5 minutes   0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp   mysql_new_db
```
- Running manage.py commands

```
$ docker ps
(venv) $ docker-compose run exec app manage.py makemigrations
(venv) $ docker-compose run exec app manage.py migrate
(venv) $ docker-compose run exec app manage.py startapp
```
[Project Link](https://github.com/ishanshre/Dockrizing-Django-and-MySql-Database)