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