Hey all, i've recently been doing some development work inside of docker containers and thought i'd reflect on my experience with it. Docker, as you are probably aware, is a set of software tools for handling application containers, which you can think of as being somewhat like the older traditional BSD jails, or a chroot on steroids.
It's getting a lot of attention because it makes deploying containers quite simple, with support for automated builds and caching built in. Using a Dockerfile allows you to build and then run a container from version control without needing to store an entire root filesystem in your version control repo.
Where it really seems to shine is in eliminating the classic "works on my machine" class of bugs: if your code runs inside of a docker container on your machine, it should run the same in a docker container on other machines.
I used to hate Docker and considered it an overengineered replacement for stuff we already have: BSD jails, chroots, LXC, Solaris zones and good old fashioned paravirtualized VMs (think Xen).
The problem, as I saw it, was that the isolation provided by Docker only really works when you rebuild your images and restart containers after changing your code, and this build process is slow if your Dockerfile is written badly. You can work around this by only putting your application's dependencies into a standard image and then bind mounting your application's code into the container, but doing that loses the isolation that makes Docker so useful in the first place.
In practice, I would often install application dependencies on my host OS directly and then run code from the git checkout to eliminate the slow build problem. Doing this brings back "works on my machine" bugs, but it also means you lose all the advantages of Docker.
When developing new code it's important to have fast build times, and you should also be able to start and stop any container you use quickly. Doing this well means making proper use of docker's caches so that rebuilds don't take forever, and to do this properly there are a few basic ways:
In practice, it makes sense to combine the above approaches depending on context: write a Makefile that can build your container from scratch but also have another version of the container that can run your code from a bind mount. Write a common base which supports either form, and then have a new Dockerfile for each.
Unfortunately Docker does not support conditionals in the Dockerfile, so you can't use a build argument to optionally run COPY commands, therefore to make life easier you should use good old-fashioned make to build each image, and put the Dockerfile for your base and for each version of your container into your version control repo.
When it's possible for me to do so, i'll be releasing a standard build system for web apps inside docker that uses these approaches. The goal is to make development work go quickly while still allowing fresh rebuilds for production deployment.