Docker, Docker Compose and Django

How to setup Django with Docker and docker-compose

In this story I'll show how to setup a simple django application to use docker and docker-compose.

Install a base django project

First we need to install a basic Django app, we do this in a Python 3 virtual environment.

$ virtualenv venv -p python3
$ source venv/bin/activate
$ pip install django
$ django-admin startproject myproject .
$ pip freeze > requirements.txt

You might have to go into the requirements.txt file and delete an annoying entry with pkg-packages 0.0.0 (or something like that).

The little dot '.' at the end tells django-admin to have a more compact directory structure.

Setup docker file to run django in container

We want to run our django project from within a Docker container. For this, we need a Dockerfile with instructions on how this shold happenn. Create a file named 'Dockerfile' and put it at the root of the project (same dir as manage.py) with this content:

FROM python:3
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8

COPY ./requirements.txt ./code/requirements.txt
RUN pip install -r /code/requirements.txt

COPY . /code/
WORKDIR /code/

FROM python:3 means that the docker container will be based off of a Python 3 image.
ENV LANG=C.UTF-8 LC_ALL=C.UTF-8: Don't quite know what this is about.
COPY ./requirements.txt ./code/requirements.txt: Copies our requirements.txt file into the container in a subdirectory.
RUN pip install -r /code/requirements.txt: Installs the requirements in the container.
COPY . /code/: Copies our project into the /code directory.
WORKDIR /code/: Sets the directory for commands like RUN, CMD, ENTRYPOINT, COPY and ADD. Better to do it this way then having multiple cd xxx & do-something.

We also want to have docker-compose start our docker container (for ease of use). So we create a docker-compose.yml file with the following content:

version: '3.2'

services:
  web:
    build: .
    command: bash -c "python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000"
    restart: "always"
    volumes:
      - .:/code
    ports:
      - "8001:8000"

command: bash -c "python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000": Runs a command in the in the docker continer created by build .. We run migrate and the test server on port 8000.
restart: "always": We want to restart on any possible change as this mimics the behavior if we didn't use docker but just ran on our host machine.

Add postgis database support

In order to add another service to our docker-compose setup, we only need to add another entry in the docker-compose.yml file. So update the docker-compose.yml to:

version: '3.2'

services:
  db:
    image: mdillon/postgis:9.6
    container_name: postgis
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=12345
      - POSTGRES_DB=projectdatabase
    ports:
      - "5433:5432"
    volumes:
      - data:/var/lib/postgresql/data

  web:
    build: .
    command: bash -c "python /code/manage.py migrate --noinput && python /code/manage.py runserver 0.0.0.0:8000"
    restart: "always"
    volumes:
      - .:/code
    ports:
      - "8001:8000"
    depends_on:
      - db

We also need to update our settings.py file in our project to take account of this new db service. In settings.py update the database settings to:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql_psycopg2',
        'NAME': 'projectdatabase',
        'USER': 'postgres',
        'PASSWORD': '12345',
        'HOST': 'db',
        'PORT': '5432',
    }    
}

Notice that as HOST we are specifing the service name from the docker-compose file 'db' and not 'localhost'. This is because the services in the docker-compose environment share the same network and communicate internally via the service names.

links

https://www.revsys.com/tidbits/celery-and-django-and-docker-oh-my/
https://www.revsys.com/tidbits/brief-intro-docker-djangonauts/