Docker isn't scary after all

This semester I am working through the second semester of a year-long senior capstone project with a group of other students. Yes, the entire first semester was research, requirements-gathering, analysis and design. Which was good experience as by the end of this I'll have seen a project through the whole SDLC from start to finish, but was also excruciatingly boring and cumbersome at times. I would not call the process so far 'agile' (in any sense).

But now that we've "completed" (quotes very intentional) the design phase of our project, we're getting ready to begin work on our prototype. Naturally, that means I'm in the market for a way to build a reproducible development environment that can also be easily transferred in an identical state (or as near as possible) to staging/production environments.

So about Docker

Our project requires Wordpress, so I need a LAMP/LEMP stack and whatever other crap Wordpress requires, plus anything else we'll end up wanting to manage builds, integration, deployment, etc., etc. I thought to myself "wouldn't it be great if I could just run Wordpress in (one or more) Docker containers that could be easily spun up with fig/docker-compose?" Each member of the group could have essentially identical development environments, pull a git repo into a volume to be mounted by Docker, and be up and running in just a couple minutes. So I set out to finally poke around in Docker for longer than a 5 minute tutorial and see what I could shake out.

It turns out that once you get the Docker "toolbox" installed correctly, this process is actually very easy! There are installers for both OSX and Windows, or a Homebrew Cask for OSX is also available. Linux users are on their own, but I'd assume you're going to do a sudo apt-get install docker-toolbox. If that doesn't work, try sudo apt-get update and then apt-cache search docker and see what shows up!

I did run in to one snag early on. I had previously installed Docker via the boot2docker method before the official Docker-toolbox was released, so I had docker components on my system. I had updated these via Homebrew, and apparently the new versions were not compatible with boot2docker anymore. I don't know if anyone else's experience is the same, but I was not at all invested in any boot2docker configurations, so I just nuked my existing versions with

brew remove docker docker-compose docker-machine

(and maybe a couple other things needed removing? can't remember now). I was pleased to discover that there is already a Brew cask for the new Docker-toolbox, so I nabbed that with

brew cask install docker-toolbox

and I was ready to get started!

Measure twice, cut once

Before I fire off the sequence of commands get this puppy going, I need some configuration to tell Docker what to run1. In this case it's docker-compose.yml. This StackExchange link was written for the old boot2docker process, but it did have a simple, clean docker-compose.yml that I used, though it will have to be modified for any actual work to get done. The author was aiming his tutorial at using docker this way for theme development, hench mounting the theme directory to a volume.

  1. I know that this can all be done via the command line, but in my opinion it's easier to conceptualize and explain this way rather than trying to decrypt really long, arcane command line flags.

Anyways, it looks like this:

wordpress:  
  image: wordpress
  links:
    - db:mysql
  ports:
    - 8080:80
  volumes:
    - .:/var/www/html/wp-content/themes/my-theme-name

db:  
  image: mariadb
  environment:
    MYSQL_ROOT_PASSWORD: example

I think that's all relatively self-explanatory, but I know not everyone is familiar with Docker or docker-compose, so I'll explain briefly. However, for the basics -- e.g. the difference between an "image" and a "container" in Docker -- see Docker docs. Here is a good place to start.

In our docker-compose.yml file -- the top level (least indented) "wordpress" and "db" tokens are going to become names for two new Docker containers, created based on Docker images from Docker's central image repository. Here we're using "wordpress" and "mariadb" (mariadb is a drop-in MySQL replacement) images, and then linking the db to the wordpress container so that the wordpress site can access the database. The port remap is so I can access the site locally at http://my.IP.address.here:8080.

The last line warrants discussion. It maps the current host directory . to (:) some theme directory in the new wordpress install on the VM located at:

/var/www/html/wp-content/themes/my-theme-name/

So in practice, I can create a new theme in my current local directory and it will be available to my wordpress site at that location inside the container for use or testing. And my changes will persist after we nuke the container, because they're saved to my local filesystem. Good times.

Start the fun

Now that we have a docker-compose configuration, we can start running some containers. First we need a virtual machine for those containers to run on! Lucky us, Docker included a tool for that exact purpose called docker-machine. Just about the most basic VM you can start would require the command:

docker-machine create --driver virtualbox nameOfVM

The docker-machine handles all the hard stuff of configuring the VM for us! The next step is to set our environment variables for docker commands using:

eval "$(docker-machine env nameOfVM)"

Note that this line can also be placed in .bash_profile or .bash_aliases for easier access -- personally I think a quick alias for regularly used VMs might be the way to go. Now that our shell knows where to find the docker daemon, we've got everything we need in place to start running containers and working with Docker! Sadly it's been easy enough to get to this point that it's almost a bit anticlimactic.

docker-compose up

should download the wordpress and mariadb images and create containers based on them, do the other things specified in our config file, and then sit there logging output to the terminal. If everything worked properly, it's deceptively simple, having successfully stripped away a huge amount of the complexity (or perceived complexity?) associated with getting started with Docker. In fact, the Docker-toolbox even has a "Quickstart Terminal" (at least for OSX, I assume also for Linux) that will even run the docker-machine commands and then leave the user with a hint or two at an open a bash terminal.

Concluding thoughts

I have some things I still want to tweak and change, because I know I don't have a setup that I can actually use for general development or plug-in development. So next on the list is probably to change the volume mounting in the config file, likely using another container to persist data between sessions. I also might look at Wocker to see if it would be a viable/better solution.

I did try out the Virtualbox / Trellis / Ansible / Vagrant / Bedrock stack, but I found it to be far more complex than this process of creating a Docker container. Oddly, I actually tried the Vagrant VM route first -- knowing that there are well-supported tools for Wordpress+Vagrant -- because I somehow thought it might be more streamlined. As I work on this project, I imagine that I will quickly discover the situations where a full Vagrant VM becomes a more suitable solution, but for now, and from my limited perspective, spinning up a Docker container is an order of magnitude less complicated and far, far faster.