Get a production-worthy Docker container for a Django application up and running in no time at all.

Notes

In case you waste your time reading this, some things this tutorial doesn’t cover:

Testing in containers

Python2. Although most of this could be translated easily (replace the 3’s with 2’s ?).

Step 0 — Application Structure

There’s no right or wrong here, but how I structure my Django projects is like so:

In this example, the application is called ‘movie’ and the entire project is called ‘moovies’. Yeah, it’s a cow-themed app for storing info about films. (A C(r)UD app?) 🐮

Step 1 — Dockerfile

So with that application structure in mind, here’s the Dockerfile.

I try to run alpine where possible as it’s incredibly lightweight. The less things you can have in a container the better. You decrease the general overhead of an image, as well as reduce potential attack surface area — containerisation is a big and upcoming security issue.

Some things of note:

Line 20 is vital to getting the migrations and static collection to run, as the app needs to be part of the PYTHONPATH.

Copy the actual source of the app after you install dependencies so that when you rebuild the image after a code change, the Docker cache knows just to rebuild the source, and not reinstall everything.

The port to expose is completely arbitrary but should match the gunicorn command.

Step 2 — Build the image

docker build . --tag moovies:v1.0

Tag your images, as it makes it easier to version them, deploy specific versions of containers etc.

Step 3- Run the container

docker run --env-file env.list -p 8000:8000 -d --name moovies-v1.0 moovies:v1.0

Here I am creating a container from the tagged image specified earlier.

Never put environment variables inside the container itself — you should always specify them at run time. In this case, I have a file called env.list which has key=value pairs of environment variables on new lines e.g.

SECRET_KEY=blah

DATABASE_URL=postgres://postgres@postgresserver:5432/postgres

which has key=value pairs of environment variables on new lines e.g. SECRET_KEY=blah DATABASE_URL=postgres://postgres@postgresserver:5432/postgres -d means run it “detached”.

Check it’s running by going to localhost:8000 (or whatever port you specified). You’ll probably get a database error.

Step 4 — Execute the Django-specific steps

docker exec -t -i moovies-v1.0 sh -c "source /etc/profile && python3 /app/moovies/manage.py collectstatic && python3 /app/moovies/manage.py migrate"

You should see console output that this was successful. If you need to create a superuser, you can ‘ssh’ into the container by running:

docker exec -t -i moovies-v1.0 /bin/sh

Then, after running source /etc/profile and ensuring you’re in the top-level Django project directory, you can run python3 manage.py createsuperuser

Step 5 — Done!

Give yourself a pat on the back. If it didn’t work for your particular project, let me know in the comments :)