Docker + Django

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
  • -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 :)