Docker Workshop

These are the instructions/background I wrote for a workshop on Docker
when we started deploying the backend services for
QuizUp as Dockers, in November 2014.

What is Docker?

It is a server and client for creating lightweight machine images, known
as containers. Currently these images can be run on Linux, in what are
known as LinuX Containers (LXC). Docker uses AUFS (a union file system)
and some clever magic to save time when creating new images.

How does it do this?

On an LXC-capable host, you can run the “docker” daemon which allows any
docker client to create new images, and start them. The images are created
using recipe files called “Dockerfiles”, which look something like this:

Note the ---> commands in between “Steps”. They are indicating when
Docker is creating a new file system layer, so in effect an image, and stores
it after every step. This makes it extremely fast to re-run docker builds
unless the build steps change. Here is the output from the same command as
above, run again, and with time in front:

Let’s analyse these messages a bit. The first one says “Sending build
context to Docker daemon 2.56 kB”. What’s happening here? Basically
your docker client is making a tarball of the directory containing your
Dockerfile and all subdirectories, and posting them along with some
metadata to port 2375 of it’s Docker host. The Docker host defaults on
every machine to unix:///var/run/docker.sock, but can be set via the
DOCKER_HOST environment variable to another machine, such as:

$ export DOCKER_HOST=tcp://192.168.22.8:2375

A common approach on OS X machines is to use a set of scripts called
“boot2docker” which basically give you a very simple interface for
downloading and running a bare-bones linux image with a docker daemon
via virtualbox. It will even tell you which environment variables to
export. See:

Exercise

Now that you’ve played around with docker a bit. It is time for an exercise.

A few weeks ago we did a little “testing kata” which was a Python Flask http
web service for making basic calculations. Since that is a common problem
(ie. creating and dockerizing a little web service) I decided to base todays
exercise on that.

When completing this exercise you will likely run into a couple of issues with
the approach of having the Dockerfile in a separate (build) folder. I solve
those issues by using a Makefile – which in it’s most simple form could start
by copying the necessary files from ../ and rm-ing them afterwards.

Since at Plain Vanilla we always tag containers with the githash (commit) of the
code they contain, I decided to hit two birds with one stone, using either the
tip of the current branch or the githash given by the GITHASH make parameter and
git archive to deliver the code.

Additionally, as new timestamps on ADD-ed files will break the Docker cache I
am extracting the timestamp for the tip of the branch and setting the modification
date for some of the files to that. Additionally I add requirements.txt manually
so that the RUN pip install -r requirements.txt step can benefit from the Docker
cache.

Your first, most basic version of the Makefile could be simpler – and mine is not
without flaws, but I decided to employ some of the slightly more advanced methods
we use in order to expose some of the trickier parts of using Docker in production.