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.