Discourse in a Docker container
about 12 years ago
Deploying Rails applications is something we all struggle with:
You would think that years along we would have made some progress in this front, but no, deploying Rails is almost as complicated as it was back in the mongrel days.
Yes, we have passenger, however, getting it installed and working with rvm/rbenv is a bit of a black art, and let us not mention daemonizing Sidekiq or Resque. Or, god forbid, configuring PostgreSQL.
This is why we often outsource the task to application as a service providers.
Last week I decided to spend some time experimenting with Docker
What is Docker?
an open source project to pack, ship and run any application as a lightweight container
The concept is that developers and sysadmins can author simple images, usually authored using Dockerfiles that provide a pristine state that encapsulate an application. It uses all sorts of trickery to make authoring of these images a painless experience and contains a central repo where users can share images.
Think of it as a VM without the performance penalty of having a VM. Docker containers run in the same kernel as the host unvirtualized.
When a user launches a “container” a private unique IP is provisioned and the process runs isolated. Docker will launch a single process inside the container, however that process may spawn others.
Docker (today: version 0.6.5) is a front end that drives Linux LXC containers and uses a copy-on-write storage engine built on AUFS. It is the “glue” that gives you a simple API to deal with containers and optionally run them in the background, persistently.
Docker is built in golang, and has a very active community.
Restrictions
Docker version 0.6.5 is still not deemed “production ready”, the technologies it wraps are considered production ready, however the APIs are changing rapidly with some radical changes to come later on.
There are plans to extract the AUFS support and probably use lvm thin provisioning as the preferred storage backend.
As it stands the only recommended OS to run Docker on by the Docker team is Ubunu LTS 12.04.03 (note, LTS ships with multiple kernels, you need 3.8 at least). I have had luck with Ubuntu 13.04, however 13.10 does not work with Docker today (since is ships with an incompatible, alpha, version of lxc). Additionally you should be aware of a networking issue in VMs that affect 3.8.
The AUFS dependency is the main reason for this tough restriction, however I feel confident this is going away, Red Hat are banking on it.
Security
It is very important to read through the LXC security document. Depending on your version of LXC, the root use inside a container may have global root privileges. This may not matter to you, or it may be very critical to you depending on your application / usage.
Additionally file mounts are a mess, if you mount a location external to the docker container using the -v options for docker run permissions are all a bit crazy. UIDs inside docker do not match UIDs outside of it, so for example:
View from the outside
View from inside the container.
There are plans to mitigate this problem. It can be worked around with NFS shares, avoiding mounts or synchronizing users and groups between containers and host.
The 42 layer problem in AUFS
AUFS only supports 42 layers. It may seem like a lot, but you hit is very early when building complex images. Dockerfiles make if very easy to reuse work when building images. For example, say I am building an image and decide to add “one more thing”. When I add a new RUN command, docker is smart enough to re-use all my previous work so building the image is snappy. As a result many docker files contain lots and lots of RUN commands.
To circumvent this issue our base image is built as a single layer. When I am experimenting with changes I add them at the end of the file, eventually rolling them in to the big shell command.
Gotchas developing with Docker
When developing with Docker it is quite easy to accumulate a pile of images you never use, and containers that have long ago stopped and are disposable. It is fairly important to stay vigilant and keep cleaning up. Any complex docker environments are going to need a very clean process for eliminating unnecessary containers and images.
While developing I found myself running the following quite a lot:
docker rm `docker ps -a | grep Exit | awk '{ print $1 }'`

Join the discussion
What do you think?
comments powered by Discourse