DEV Community

Mahesh Prajapati
Mahesh Prajapati

Posted on

Docker-compose-ing a Django App - for complete starters

In the earlier post, in which I described about writing a simple Dockerfile for a Django App.

We will pickup where we left off earlier. If you are completely new to Docker, I recommend checking the previous post first.

The starter code that we are using for this post is available in GitHub if you want to follow along.

Let's see how the file structure looks before we start:

├── Dockerfile
├── manage.py
├── README.md
├── requirements.txt
└── main
    ├── asgi.py
    ├── __init__.py
    ├── settings.py
    ├── urls.py
    └── wsgi.py
Enter fullscreen mode Exit fullscreen mode

If you are following from the previous post, you will notice I have renamed the 'main' project folder from todo to main. It's because I want to scale this tutorial series to use as a starting template for future projects. So I felt it's important to keep the folders' name as generic as they can be.

The folder structure shouldn't seem to be too confusing as they are not complicated to understand.

Let's go forward. First of all, create a directory in project root called app and move all existing contents to the app folder, so the folder structure now looks like:

.
├── app
│   ├── Dockerfile
│   ├── entrypoint.sh
│   ├── main
│   │   ├── asgi.py
│   │   ├── __init__.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── manage.py
│   └── requirements.txt
└── README.md

3 directories, 12 files
Enter fullscreen mode Exit fullscreen mode

Why do this? It's because we are incorporating docker-compose which by its nature, allows us to manage multiple tools for our project, django being one of them. Each of those tools and their configs should go to their respective directory for clear code and readability.

Now, let's create a docker-compose.yml file at the root directory, which now contains the app directory and write the following lines of code.

version: "3.8"

services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./app:/app
    ports:
      - "8000:8000"
    env_file:
      - ./app/.env
    environment:
      - DEBUG=1
Enter fullscreen mode Exit fullscreen mode

Let's go through the code and see what's happening
1.

version: "3.8"
Enter fullscreen mode Exit fullscreen mode

We want to use docker-compose version 3.8. How does this versioning matter? That's a lot of complex topics for this post, but if you want to know more, you can check official docker website.

2.

services:
Enter fullscreen mode Exit fullscreen mode

We want to list the 'tools' as mentioned earlier as array items within the services.

3.

  app:
Enter fullscreen mode Exit fullscreen mode

Each of the 'tools' needs their own name as recognition. app is just a generic name for the django container. You can put anything instead of app like django, server or even labrador.

4.

    build:
      context: ./app
      dockerfile: Dockerfile
Enter fullscreen mode Exit fullscreen mode

As we know, each 'tool' or container in docker languages, needs to build before we run. We learnt that in the previous post as well. docker-compose needs to know which folder to look for to build the container app. So, naturally, we put all the files related to the app container into app folder and gave the context name to ./app, as in app folder from where docker-compose.yml file is located.

At the same time, it also asks for Dockerfile location. So the name and location, relative to the folder provided in context. We may want to have multiple Dockerfiles later on, so it is convenient to have them in easy-to-remember place

5.

    command: python manage.py runserver 0.0.0.0:8000
Enter fullscreen mode Exit fullscreen mode

If you understand Django, this is just a standard run command which we want to do when we start the server later on.

6.

    volumes:
      - ./app:/app
Enter fullscreen mode Exit fullscreen mode

The volumes mapping allows us to map local folders to folders inside the container. If you look into Dockerfile, we created a folder named app. The folder inside the container and local system stay synchronized with this command. It also triggers hot reloading of server whenever we change something in local system, so it's very important to keep it on while debugging. Else, we will have to restart the server on every code change.

7.

    ports:
      - "8000:8000"
Enter fullscreen mode Exit fullscreen mode

Just like the previous post, we want to map our local port 8000 to container's port 8000 to access the server.

With this, you can remove the lines 7. EXPOSE 8000 and 8. CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] Since, both of them are now managed by docker-compose herein.

8.

    env_file:
      - ./app/.env
    environment:
      - DEBUG=1
Enter fullscreen mode Exit fullscreen mode

Both env_file and environment can be used to set environment variables to the container. environments are preferred when the variables are public, whereas env_files which are usually git-ignored, can be used to set private environment variables like secret-keys, tokens and even passwords. We will look into how to use them later on.

For now, lets go to the terminal and hit up

docker-compose build
Enter fullscreen mode Exit fullscreen mode

If everything went fine, you may now see Successfully built in the terminal.

So, we may now fire up the server by running

docker-compose up
Enter fullscreen mode Exit fullscreen mode

We should now be presented with this beautiful screen when we navigate to localhost:8000 in our browser.
Django Starting Page

That's all it takes to run our django project with docker-compose. As simple as it can get.

All the code is available in GitHub

Up next, we will add postgres database and nginx reverse proxy to the setup and find-out how docker-compose systems can be scaled up.

Top comments (1)

Collapse
 
ds_devto profile image
DS

Concise and to the point article. Thanks. When are you planning to write next parts of this series for postgres and nginx?