Containerizing a Django app with Docker and Docker-compose

Containerizing a Django app with Docker and Docker-compose

Running application components in containers

In the previous article I introduced docker to you and showed how it can be used with a Django project. We also saw how we can run an app in a container in our local system.

In this write up, I will be taking it a step further with the same codebase which we'll fetch from github, showing how to run different services used by our application by employing a more effective tool for this use-case, called docker compose. For example, if our application has a database service, cache service etc., each of this services can be run together but in separate containers or environment and and our application would still work as expected. The instructions for the different services are usually defined in YAML file usually name docker-compose.yml.

Fetch our code from github.com/toyetola/tutorial

To fetch, RUN

github clone https://github.com/toyetola/tutorial

You would see your project cloned into #tutorial directory

blogpost-folderview.PNG

Now create a file docker-compose.yml in the root folder named tutorial

version: "3.9"

services:
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"

This file is uses a version of docker-compose 3.9. It hen introduces that makes up our application with the keyword 'services'. The 'web' service uses the Dockerfile in the project root directory to build the project and then runs the coomand on a local ip in the container and on the container port 8000. The command maps the host system port to the container's port 8000.

I will like to intruduce a database other than the default SQLITE database as we are running a multi-container system and we need to show that in our compose file and see how these indivdual containers that runs the different parts of our applications comes to work together.

Go to settings.py in your project folder and edit the DATABASE section to reflect the following changes:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': env('POSTGRES_NAME'),
        'USER': env('POSTGRES_USER'),
        'PASSWORD': env('POSTGRES_PASSWORD'),
        'HOST': env('DATABASE_HOST'),
        'PORT': env('PORT')
    }
}

Create a .env file in the root directory of your project, this stores your environment variables as it best practice to not use actual values of your secret keys and other database config values in your settings file. To make the .env file readable from settings.py, you will nead a django package that helps with this named django-environ

RUN python -m pip install django-environ

In setting.py:

At the top of the file after the Path import

import os
import environ

Cast DEBUG to default to FLASE if not read from .env

env = environ.Env(
     DEBUG = (bool, False)
)

#Take environment variables from .env file
environ.Env.read_env(os.path.join(BASE_DIR, '.env'))

Your .env file looks like this:

SECRET_KEY=django-non-serious-key&blatheblafkfhh&^%dhhdh(@&*JHFG*
POSTGRES_NAME=example
POSTGRES_USER=mydbuser
POSTGRES_PASSWORD=mydbpassword
DATABASE_HOST=192.168.23.4
DEBUG=1
DATABASE_PORT=5432

Please note: that you would need to down POSTGRESQL on your machine. You can easily do this by downloading PgAdmin. This helps you with a lot of setup automatically.

pgAdmin.PNG When you install PgAdmin, this is the interface that allows you login as a user or create a user account.

Now update the docker-compose.yml file with the following code which represent the database service and defines the structure on which the container for this service is built.

services:
  db:
    image: postgres
    volumes:
      - ./data/db:/var/lib/postgresql/data
    environment:
      - POSTGRES_NAME=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
  web:
    build: .
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - .:/code
    ports:
      - "8000:8000"
    environment:
      - POSTGRES_NAME=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    depends_on:
      - db

Next RUN docker-compose up to build and export a container image of our entire application.

You will see in your docker desktop your running container services

container-services.PNG

When you click on the "open in browser" button that shows up hovering on the tutorial_web_1 container service, it leads you to localhost:8000 with this view.

django-in-container.PNG

To see your applications image created by docker

RUN dock image ls

imagelist.PNG

Let share our app, we could share it to any online registry e.g. Dockerhub, Google Container registry etc. We would be using docker hub, you might wan to create an account on hub.docker.com. Login via your docker desktop

In your terminal, while in the root directory of your project;

Now tag your image to specify how it will be uploaded to docker hub

RUN docker tag <IMAGE-ID> yourdockerhubusername/tutorial_web:v1

e.g.

docker tag 9ad4ec1c5b59 yourdockerhubusername/tutorial_web:v1

Push to docker hub

RUN docker push yourdockerhubusername/tutorial_web:v1

VIOLA!!!

We just got our application and its dependent services running in containers. Let me know if this has helped you and if you have questions I am available to answer your questions in the comments.

Check this branch for correct code: github.com/toyetola/tutorial/tree/compose-l..