I’ve used Vagrant a fair amount in my day, and it’s great. I enjoy being able to spin-up toy linux environments to test out ideas. I tend to use the Chef provisioner with Vagrant to build-out a local environment that matches my server fairly closely.

My Ever-Evolving Rant About DevOps

I’ve been thinking about Chef a lot lately. Often is the time, in moments of profound frustration, that I’ve had the thought that Chef is nothing more than a useless, leaky abstraction that separates me from something I know fairly well—Linux.

This thought is usually fleeting: Chef provides many needed abstractions that are, ultimately, much easier to grok than the underlying Linux system. Further, Chef allows you to keep a(n ostensibly) well-tested system under version control.

I’ve come to the realization that my problem with Chef is not really a problem with Chef, but a problem with Linux itself.

Linux system administration is difficult because Linux commands are non-deterministic and rely heavily on system state (e.g., installed software, permissions, network settings and availability). Maintaining a bare-metal, long-running server non-interactively using Chef sucks because any hand-tinkering via ssh is going to fuck with the “state” of the system—creating different results for subsequent chef-client runs. This system state adjustment may or may not be reflected in the chef repository (which double sucks).

Why Docker Curtails My Rage

I started to think about Docker. I feel Docker addresses the problem of program state better than other currently available solutions (although, Nix is looking pretty promising as well). While Docker is still a Linux system—and, ipso facto, state-dependant—it’s also ephemeral and therefore, by not persisting changes to state, Docker has created a previously unavailable (on bare metal hardware), lightweight workaround to the problem of system state.

As is my wont, I decided today to play a bit with Docker on Vagrant and, lo-and-below, I found that the newest version of Vagrant (1.6.2, as of May 26th) can actually use docker as a provider, that is, as an alternative to VirtualBox. Using Docker as a provider means that you can run a fully-independent development enviroment, on your host machine without the overhead of VirtualBox. Neat.

“Imma setup a local development environment for Ubuntu 14.04, nginx and php-fpm using Vagrant, Supervisord and Docker,” says I.

Project Layout

To keep my project directory nice and tidy, I’ve separated-out most of the files needed by the Docker provider into a Docker folder. This results in the directory structure below.

The Dockerfile is used to build the main docker machine and the subfolders in the Docker directory contain configuration used in the Dockerfile.

The www folder is my fake php project folder.

VagrantFile

Since docker handles so much of what was previously handled by Vagrant provisioner, the Vagrantfile for a Docker-backed Vagrant instance is pretty sparse.

In mine, I’ve got:

Dockerfile

Most of the work of provisioning a container is handled by Docker and the Dockerfile. In fact, if you were only ever going to run this container on a Linux machine, I don’t think that Vagrant adds any needed functionality to the docker.io cli. In terms of portability, however, Vagrant is, at this time, a necessary evil to run docker on OSX and Windows.

This Dockerfile takes care of building a docker container from the latest Ubuntu image (14.04 as of May 26th, 2014). Running this code installs:

  • Nginx 1.6.0
  • PHP 5.5.9
  • Supervisor

This config also starts supervisor with the --nodaemon flag by default. Docker can run a container running a non-daemonized program as a daemon (much like supervisor can run non-daemonized programs as daemons). Supervisor is used as a way of running both nginx and php-fpm as non-daemonized programs. It is also noteworthy that the dockerfile creates and/or modifies configuration files for php-fpm and nginx to make sure they both run in non-daemon mode.

nginx/default

php-fpm/php-fpm.conf

supervisor/supervisord.conf

Jam Time

With all of our configuration in place there isn’t much left to do aside from running the vagrant instance and allowing docker to create our container.

With that, you now have a container running nginx and php-fpm that is sharing a folder with you at /var/www. Navigating to http://localhost:8080/index.php should show you the contents of your ./www/index.php file.

This process is really simple AND super lightweight. I’ve been running my docker/vagrant instance for about 45 minutes alongside chrome and tmux/xterm without any noticeable jankyness on a notoriously janky laptop.