Django development using Docker as host - Part 4: docker-compose
Tags: django, docker, devops, devjournal
Published: 2021-01-17 07:27:41

In the previous step, we initialized the Django application using the docker image.

In this part, we will be creating the `docker-compose.yml` file and define the required services to run the application.

## TOC
1. [Create directories](#p4-create-directories)
2. [Create `docker-compose.yml`](#p4-docker-compose)
3. [Define database (MySQL) service](#p4-database)
4. [Define adminer server (Database management)](#p4-adminer)
5. [Define app service](#p4-app-service)
6. [Run docker-compose](#p5-run-docker-compose)

## Let's start

### 1. Create directories <a name="p4-create-directories"></a>
Create two directories at the root of the project, `src` and `static_my_project` in the host where source code of the Django application will reside in the `src` directory and the static files in the `static_my_project` directory.
The directory structure will look like
```
- /
  | - scripts
  | - src
  | - static_my_project
  | - docker-compose.yml
  | - Dockerfile
  | - requirements.txt
```

### 2. Create `dokcer-compose.yml` <a name="p4-docker-compose"></a>
Create the `docker-compose.yml` file in the host with the content
```
version: '3.7'
```

### 3. Define database service <a name="p4-database"></a>
Let's define a database service that will be consumed by the Django application.
Add the following to the `docker-compose.yml`
```
services:
  database:
    image: mysql:8.0
    container_name: app__database
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    volumes:
    - app_db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=app_db
      - MYSQL_DATABASE=app_db
      - MYSQL_USER=app_db
      - MYSQL_PASSWORD=app_db
    ports:
    - 3306:3306

volumes:
  app_db:
```
* We are using `mysql` version `8.0` image for the database.
* We have also defined a docker volume to store database files inside `app_db`.
* The database will be running on port `3306`.

### 4. Define adminer server (optional) <a name="p4-adminer"></a>
[**Adminer**](https://registry.hub.docker.com/_/adminer) is a web-based database management service. Using this service we can directly access the database in the browser.
Add the following content to the `docker-compose.yml` file
```
services:
  adminer:
    image: adminer:latest
    restart: always
    ports:
    - 8080:8080
```
The `adminer` services will be running on port `8080`.

### 5. Define app service <a name="p4-app-service"><a/>
Let's create an application service. We will use the `Dockerfile` to build the image.
Add the following content to the `docker-compose.yml` 

```
services:
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: app_image
    command: ["/scripts/docker/wait_for_it.sh", "database:3306", "--", "/scripts/docker/docker_start.sh"]
    depends_on:
      - database
    ports:
    - 8000:8000
    volumes:
    - ./requirements.txt:/app/requirements.txt
    - ./static_my_project:/static_my_project
    - ./src:/app
```
* The application will be build using the `Dockerfile` we created in step 1
* When running, the application container will be named `app_image`
* Django by default runs on port 8000, we have mapped the port 8000 of the host to the container so that the server can be accessed from the host browser.
* We have mapped the following host volumes to the container files/folder.
  * `requirements.txt` -- Any modification to the requirements.txt file in the container will be updated to the host requirements.txt file
  * The `static_my_project` directory of the host will be mapped to the `static_my_project` directory in the container.
  * The `/app` directory is mapped to the `./src` directory in the container. Any changes to the host `./src` or container `/app` directory will be synced.

---

The contents of the `docker-compose.yml`

```
version: '3.7'

services:

  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: app_image
    command: ["/scripts/docker/wait_for_it.sh", "database:3306", "--", "/scripts/docker/docker_start.sh"]
    depends_on:
      - database
    ports:
    - 8000:8000
    volumes:
    - ./requirements.txt:/app/requirements.txt
    - ./static_my_project:/static_my_project
    - ./src:/app

  database:
    image: mysql:8.0
    container_name: app__database
    command: --default-authentication-plugin=mysql_native_password
    restart: always
    volumes:
    - app_db:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=app_db
      - MYSQL_DATABASE=app_db
      - MYSQL_USER=app_db
      - MYSQL_PASSWORD=app_db
    ports:
    - 3306:3306

  adminer:
    image: adminer:latest
    restart: always
    ports:
    - 8080:8080

volumes:
  app_db:
```

### 6. Run docker-compose <a name="p5-run-docker-compose"></a>
To run the defined services inside the `docker-compose.yml` file, let's run the services by executing
```
docker-compose up --build
```
It will build the application image and run the services.

Let's verify first if `database` and `adminer` services are running. Open the following link in the browser
```
http://localhost:8080
```
If the `adminer` login page appears, enter the following details
* Server: database
* Username: app_db
* Password: app_db
* Database: app_db

If the login works, the `database` and the `adminer` services are successfully running.