Setting up a development environment for a web application can seem simple—just use SQLite and WEBrick or a similar development server—but taking shortcuts can quickly lead to problems. What happens when you need to onboard new team members? What if your team members are geographically distributed? How do you prevent bugs from creeping in when the production environment's configuration drifts away from the development environment? Even if you've managed to set up a picture-perfect development environment, what happens when a developer inevitably breaks its configuration?
In the last few years a huge number of DevOps tools have sprung up to help teams automate the provisioning and configuration of their infrastructure. These include Puppet, a configuration management tool, and Vagrant, a tool to automate the management and provisioning of development environments. While these tools are often thought of as being most useful for Ops staff, this tutorial will show how they can be used to manage a development environment for a team working on a web application.
By taking advantage of the infrastructure-as-code approach of these tools, the configuration of environments can be version controlled along with the source code for the application itself. This allows developers to work in extremely realistic environments, often identical to those managing a production application, while reducing the overhead involved in managing the environment. It also significantly decreases the onboarding cost for a new developer: All they have to do is clone a repository, run a few simple commands, and they have their own copy of the environment up and running. Most importantly, it means that any changes to the setup to the environment can be immediately reflected across all copies of the environment through the use of version control systems.
In the first part of this tutorial, we'll be examining how to use Vagrant to automate away the pain of managing VMs on your local system. The next part of the tutorial will show how to use Puppet's powerful declarative language to simply describe the elements of your environment and their relations to each other. By the end of the series, you'll be able to define a powerful, reusable development environment with just a few simple configuration files. This tutorial is oriented towards web application development, and will show how to configure a VM to run apache on code shared from your local machine.
Using Vagrant to Manage VMs
Vagrant is a configuration-centric tool for managing VMs on your local machine. Using Vagrant, you only need to write a simple file specifying certain attributes you want your system to have, and Vagrant takes care of provisioning and managing the VM for you. It also provides an elegant command line interface for interacting with the VMs.
In order to get started with Vagrant, you'll need to download the appropriate version of VirtualBox for your system, since that's what Vagrant uses on the backend. You'll also need to grab the Vagrant package for your distro and add
/opt/vagrant/bin to your
$PATH. In the examples we'll be using Debian 6.0, but all you should need to change is which packages you grab and install.
$ wget http://download.virtualbox.org/virtualbox/4.2.6/virtualbox-4.2_4.2.6-82870\~Debian\~squeeze_i386.deb $ sudo dpkg -i virtualbox-4.2_4.2.6-82870\~Debian\~squeeze_i386.deb $ wget http://files.vagrantup.com/packages/476b19a9e5f499b5d0b9d4aba5c0b16ebe434311/vagrant_i686.deb $ sudo dpkg -i vagrant_i686.deb
We'll also need to grab a boxfile. Boxfiles are the base images Vagrant builds its VMs on, specifying things like disk capacity and the installed operating system. For our environment we'll grab a simple boxfile for a Lucid 32-bit system:
$ vagrant box add lucid32 http://files.vagrantup.com/lucid32.box
Creating a Source-Controlled Development Environment
Now we can create a directory for our dev environment. We'll also go ahead and initialize it as a git repository.
$ mkdir sample-dev-env $ cd sample-dev-env $ touch Vagrantfile $ git init $ git add Vagrantfile $ git commit -m "Starting our new dev environment"
The Vagrantfile we've just created is the central configuration file that Vagrant uses to determine the configuration of the VMs it manages. You can automatically generate a sample Vagrantfile with lots of documentation in it by running
vagrant init, but for now we'll just set up our own Vagrantfile to configure one VM with the boxfile we've added, and set it up to forward port 80 on the VM to port 3000 on our local machine so we can access the webapp being run on the VM on our local machine:
Vagrant::Config.run do |config| config.vm.box = "lucid32" config.vm.forward_port 80, 3000 end
That's it! Vagrant automatically shares any files in the project directory to a shared folder located at
/vagrant on the VM, so if we just put our web app folder into the dev env directory and execute
vagrant up, vagrant will bring up a virtual machine with our code on it. Accessing that virtual machine is simplified by the use of
vagrant ssh, the ssh wrapper Vagrant provides for accessing your VMs.
$ vagrant up $ vagrant ssh $ ls /vagrant Vagrantfile your_webapp_here
Now that we have a Vagrantfile that defines our basic configuration, we can commit our changes to our dev env git repo:
$ git add Vagrantfile $ git commit -m "Basic Vagrantfile"
Of course, that still leaves us with a lot of work to do: how do we make sure the necessary libraries and packages are installed? How do we ensure the webapp is running? How do we configure the system so that Apache can find our web application? In the next part of this tutorial, we'll learn how to use Puppet to provision our Vagrant-managed virtual machines, so that developers can go from scratch to having a working VM serving your app just by cloning your repository and running
- Read part 2: Build a Web Dev Environment With Vagrant and Puppet
- Watch Mitchell Hashimoto speak at PuppetConf about advanced Vagrant use with Puppet
- Read Mitchell's take on building stronger DevOps culture with Puppet and Vagrant