Testing a Django app with Docker

I've been playing around with Docker a fair bit and recently hit upon a configuration that works nicely for me when testing code at work.

The basic premise is that I run a docker container that pretty well emulates the exact environment that the code will run in down to the OS so I don't need to care that I'm not running the same distribution as the servers we deploy to and that I can test my code at any time without having to rebuild the docker image.

Here's an annotated Dockerfile with the project-specific details removed.

# We start with ubuntu 14.04

FROM ubuntu:14.04
MAINTAINER Steve Engledow <steve@engledow.me>

USER root

# Install OS packages
# This list of packages is what gets installed by default
# on Amazon's Ubuntu 14.04 AMI plus python-virtualenv

 RUN apt-get update \
     && apt-get -y install software-properties-common git \
     ssh python-dev python-virtualenv libmysqlclient-dev \
     libqrencode-dev swig libssl-dev curl screen

# Configure custom apt repositories
# and install project-specific packages

COPY apt-key.list apt-repo.list apt.list /tmp/

# Not as nice as this could be as docker defaults to sh rather than bash
RUN while read key; do curl --silent "$key" | apt-key add -; done < /tmp/apt-key.list
RUN while read repo; do add-apt-repository -y "$repo"; done < /tmp/apt-repo.list
RUN apt-get -qq update
RUN while read package; do apt-get -qq -y install "$package"; done < /tmp/apt.list

# Now we create a normal user and switch to it

RUN useradd -s /bin/bash -m ubuntu \
    && chown -R ubuntu:ubuntu /home/ubuntu \
    && passwd -d ubuntu

USER ubuntu
WORKDIR /home/ubuntu
ENV HOME /home/ubuntu

# Set up a virtualenv andinstall python packages
# from the requirements file

COPY requirements.txt /tmp/

RUN mkdir .myenv \
    && virtualenv -p /usr/bin/python2.7 ~/.myenv \
    && . ~/.myenv/bin/activate \
    && pip install -r /tmp/requirements.txt \

# Set PYTHONPATH and activate the virtualenv in .bashrc

RUN echo "export PYTHONPATH=~/myapp/src" > .bashrc \
    && echo ". ~/.myenv/bin/activate" >> .bashrc

# Copy the entrypoint script

COPY entrypoint.sh /home/ubuntu/

EXPOSE 8000

ENTRYPOINT ["/bin/bash", "entrypoint.sh"]

And here's the entrypoint script that nicely wraps up running the django application:

#!/bin/bash
. ./.bashrc
cd myapp/src
./manage.py $*

You generate the base docker image from these files with docker build -t myapp ./.

Then, when you're ready to run a test suite, you need the following invocation:

docker run -ti --rm -P -v ~/code/myapp:/home/ubuntu/myapp myapp test

This mounts ~/code/myapp and /home/ubuntu/myapp within the Docker container meaning that you're running the exact code that you're working on from inside the container :)

I have an alias that expands that for me so I only need to type docked myapp test.

Obviously, you can substitute test for runserver, syncdb or whatever :)

This is all a bit rough and ready but it's working very well for me now and is repeatable enough that I can use more-or-less the same script for a number of different django projects.