A Development Workflow with Vagrant + Ansible

I can’t tell you how many times I’ve screwed up some package installation or the OS X installation conflicts with homebrew’s installation to the point where I lose a day or two of work time trying to get back in a working state. My experience with installing packages on OS X is that it never 'just works'. My latest adventure was upgrading from Mountain Lion to Mavericks. I sent out a tweet "Upgrading to Mavericks. Wish me luck.” the morning I started the upgrade. I thought I had accounted for the known issues like Java 1.6 getting blown away and having to search for the install on Apple’s support site, but I’m still suffering the wrath it played on my machine.

I often have a number of projects in progress at once or that I need to be able to pick up at a moments notice. Each project is different, has different needs, and often is a different tech stack. Over the last few weeks, I’ve encountered some issue or another with each project. At one point, I found the group id of all my user's files was mysteriously changed to a random one.

As I continued with my Mavericks upgrade that grey day in April, friends tweeted back at me all the things I would need to account for that they had run into. A few tweeted alternatives (use nginx instead of apache, use homebrew instead of the OS X pkg), none of which I am opposed to. But having to swap something (or multiple somethings) out from under a project that was already running can be risky. Making too many changes at once makes it difficult to pinpoint issues later. Iteratively build software, right?

A couple people tweeted back at me: Vagrant!!! Use Vagrant! I've been putting this off for too long. I needed something that is repeatable, version controlled, lightweight, and portable (for when I order the next MacBook Pro, of course). And so my adventure began to get up to speed on how to integrate Vagrant into my development workflow.

Getting Started

I spent my first bit of time reading through Vagrant’s Getting Started docs. Within a few minutes, I had a basic Ubuntu box up and running with Virtual Box and a simple Apache web server, serving "Hello World!". I was pleasantly surprised at the quality of the documentation for Vagrant and quickly skimmed the rest of the docs outside of the Getting Started section.

Next I decided to spin up a box that will support my Rails development efforts. I searched GitHub for "Vagrantfile" for examples to start out with.

The Basic Requirements

Ubuntu or CentOS box with Git, Ruby (rvm, bundler), Postgresql, and the Heroku Toolbelt.

At this stage, I only wanted one box. Get the simplest possible thing working first.

Vagrant

The Provider

For local development, I decided on the default provider, VirtualBox, as I am already familiar with it and it's free.

The Provisioner

As for the provisioner, I quickly settled on Ansible. I've heard rumors that it's pretty easy to grok. The docs suggest using a shell script provisioner if not familiar with Ansible, Puppet, Chef, or the others, but since I've done plenty of automation with shell scripts in the past, it made sense to step it up to the next level. So Ansible it is.

Ansible

At a high level, Ansible consists of a *playbook* which runs *tasks* which can trigger *handlers*.

With each Ansible task, I was able to install apt packages, configure postgresql, create application databases with specific user access. Whatever you do in a shell to install and configure the machine, you should be able to do with Ansible.

The Development Workflow

The development workflow with this approach is very similar to my previous workflow. The only difference is SSHing into the vagrant box every once in awhile to start an app server (which will be automated at some point). I'm able to use my preferred IDE and a smorgasboard of browsers on my local machine. It was a very natural transition, which is one reason why I've been resistant to use tools like these paired with yet another virtual machine in order to do development. I am looking forward to having a more productive development workflow.

Conclusion

My impressions of Vagrant and Ansible are very positive. While my use case is pretty basic right now, I found the Ansible tasks easy to read and learn. I was quickly writing my own tasks with only the help of the Ansible module docs. I liked not having to worry about setup on the guest machine, like a client being available to run Ansible tasks. Instead, everything runs on the guest machine over SSH.

Early on in my adventure I could see how useful this would be for my development workflow. I'm looking forward to having my environments automated, repeatable, and to have dev and production environment parity. Another use of Ansible is for application deployment. I'm interested to see this use in action so this will be the next use I look at.

Are you using Vagrant or Ansible or a different toolset to automate your workflow? Please share!

The Code

The example code for this can be found on github here. Feel free to use and improve this. Feedback welcome!