Setting up Docker environment for Django.

You can access the source code for this tutorial from my git repository here.

What is Docker?

Docker packages and runs an application in an isolated environment called a container.

This Container contain everything you need to run the application.

What do I mean by everything?

Imagine you are building a web application that requires a frontend, backend, and a database. All these services have to be installed and configured whether it be on your laptop or a production server running in the cloud.

I’ve had experiences where it has taken hours to setup a new development environment on my Mac for an application requiring multiple services, binaries, libraries and configuriation files. Once I have all these services up and running on my Mac OS there is no guarantee that is application will run on a Windows os which leads us to the old problem, “Well it worked on my server.”

Docker eliminates all that. All that is required to spin up a complete development environment with your application is to pull your “dockerized” app from the DockerHub repository or from your git repo, then cd into the root of your project and launch your app from the terminal with a few Docker commands.

It’s easy now to share this Dockerized app with a new team member whether they are working on a Mac, PC, or Linux, as long as they have Docker installed they can spin this Dockerized app up and have it running in a matter of minutes in its own isolated environment where the app is guaranteed to work.

What is Django?

Django—pronounced “Jango,” named after the famous jazz guitarist Django Reinhardt—is a web application framework that allows rapid development of complex, database-driven websites which uses the model–template–views (MVC) pattern.

We’re going to be building a Docker development environment for a bare bones Django installation running Postgresql database. When we’re finished we will be able to spin up this Django app in its isolated Docker development environment where you can begin building out your Django application.

Server Architecture

Here’s a overall look of the server architecture we will be building.

Setup the Django Project File Structure

mkdir dockerized-django
cd dockerized-django
mkdir server
touch docker-compose.yml
touch Makefile
touch .env
git init
cd server
touch Dockerfile
touch requirements.txt
cd ..

Project Files

  • dockerized-django
    • server
      • Dockerfile
      • requirements.txt
    • .env
    • docker-compose.yml

Create the Dockerfile

cd server
sudo nano Dockerfile

Put to the following into the Dockerfile.

# /dockerized-django/Dockerfile

FROM python:3
ENV PYTHONBUFFERED 1
RUN mkdir /server
WORKDIR /server
COPY requirements.txt /server/
RUN pip3 install -r requirements.txt
COPY . /server/

CMD python manage.py collectstatic --no-input;python manage.py makemigrations;python manage.py migrate

To save exit with nano use ctrl-o (as in olive) => return => ctrl-x

Create the .env file

sudo nano .env

Add the following to our .env file:

DATABASE_NAME=db_django
DATABASE_USER=user_django
DATABASE_PASSWORD=mypassword
DATABASE_HOST=database
DATABASE_PORT=5432
SERVER_PORT=5555
DJANGO_SETTINGS_MODULE=django_proj.settings

Populate the Docker Compose File

# dockerized-django/docker-compose.yml

version: '3'

services:
    database:
        container_name: database
        image: postgres:latest
        environment:
            - POSTGRES_DB=$DATABASE_NAME
            - POSTGRES_USER=$DATABASE_USER
            - POSTGRES_PASSWORD=$DATABASE_PASSWORD
            - POSTGRES_PORT=$DATABASE_PORT
        volumes:
            - ./postgres-data:/var/lib/postgresql/data
    server:
        build: ./server
        container_name: django
        ports:
            - '$SERVER_PORT:$SERVER_PORT'
        command: python manage.py runserver 0.0.0.0:$SERVER_PORT
        environment:
            - DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
        volumes:
          - ./server:/server
        depends_on:
            - database
volumes:
  postgres-data:

Data Persistence

Note the highligted line above on ./postgres-data:/var/lib/postgresql/data where we map the data from Postgres running on the Docker container into a directory on our host machine. This insures that as we won’t lose any data from the database even if we were to spin down the app with docker-compose down we won’t lose our data.

Since we are referencing postgres-data in our database volumes we also need to add volumes at the bottom of our docker-compose.yml file.

Django requirements.txt File

Django>=2.0,<3.0
psycopg2>=2.7,<2.9

Create the Django Project

# create django project
docker-compose run server django-admin startproject django_proj .

# create django app
docker-compose run server django-admin startapp django_app

We now should have our Django project and app installed in the root of the server directory

At this point if we were to spin up the app, Django would be using Sqlite but we want Postgres for our database. So, lets swap out Sqlite for Postgres in the server/django_proj/settings.py file:

Replace Sqlite with Postgres

vi server/django_proj

Scoll down the settings.py file and replace:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

… with:

DATABASES = { 
'default': { 
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': 'db_django',
    'USER': 'user_django',
    'PASSWORD': 'mypassword',
    'HOST': 'database',
    'PORT': 5432, 
  }
}

Now that we have Django referencing Postres we can move on with migrations.

Migrate and Create the Django App

# migrate
docker-compose run server python manage.py migrate
docker-compose run server python manage.py createsuperuser

Add Django App to Settings.py

# server/django_proj/settings.py

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_app',
]

Test Server

We are now ready to test the server by accessing the Django admin UI from a browser.

Spin up the database and server services:

docker-compose up -d

Sometimes docker-compose up -d fails to bring our django server, if that happens its usually because the server came online before the database so, if that happens manually bring the database first and then the server:

docker-compose up -d database
docker-compose up -d server

Now you should be able to access the Django in your browser at http://localhost:5555.

We can access the Django admin page at at http://localhost:5555/admin.

Accessing the Django Logs File

Docker-compose has a wonderful command to display the different services logs to the command line which is great for debugging.

# display logs for both database and server
docker-compose logs

# display only the logs for the database
docker-compose logs database

# display only the logs for the server
docker-compose logs server

Now if you do run into any errors you can refer to the log files for each service.

Commit All Work to Git

Before commiting our work to git let’s create a .gitignore file so our db_backups directory is not commited along with the rest of the files to the git repo.

touch .gitignore
sudo nano .gitignore

Add the following to the .gitignore file:

# dockerized-django/.gitignore
*.py[co]
__pycache__

./db_backups
git add .
git commit -m "initial commit"

Git Repo for Dockerized Django

You can access my source code from my git repository here and use it as a boilerplate.