SEI Insights

DevOps Blog

Technical Guidelines and Practical Advice for DevOps

DevOps Technologies: Vagrant

Posted on by in

Environment parity is the ideal state where the various environments in which code is executed behave equivalently. The lack of environment parity is one of the more frustrating and tenacious aspects of software development. Deployments and development both fall victim to this pitfall too often, reducing stability, predictability, and productivity. When parity is not achieved, environments behave differently, which makes troubleshooting hard and can make collaboration seem impossible. This lack of parity is a burden for too many developers and operational staff. Looking back on almost every problem I have seen in new production deployments, I find it hard to think of one issue that wasn't due in some part to lack of parity. For developers, this pain is felt when integrating and testing code.

In a traditional sense, the problem is already solved. Virtualization is old news, even for personal machines, enabling developers to recreate the actual deployment target platforms for their local development. Provisioning an environment is a somewhat older trick with origins as old as shell scripts, made even more robust with the advent of automated environment provisioning tools like Chef and Puppet. So, why is parity still an issue? Or is it?

The job of an operations team often involves implementing full parity across deployment environments, such as those used for testing, staging, and production. Conversely, the development team is almost entirely responsible for provisioning development machines. To achieve 100 percent parity between both sets of environments, both teams must speak the same language and use the same resources.

Chef and Puppet, both crafted for the operations role, are just slightly out of reach for a busy developer. Each has a respectable learning curve, and neither really solves the parity problem completely: developers still need to virtualize the correct production target platform. All this additional work incurs a decent amount of overhead when you just want to write code!

This is where Vagrant comes in. Vagrant is a developer's tool that basically serves up a virtualized and provisioned environment to developers using operations tools with a single, declarative script and a simple command-line interface. Vagrant cuts out the grunt work needed to stand up a virtual machine (VM) and it removes the need to configure or run, for example, chef-server and chef-client. Vagrant hides all of this and leaves the developer with a simple script, an extensionless file named Vagrantfile, which can be checked into source control along with the code.

Let's look at an example Vagrantfile that stands up and provisions a RHEL 6.5 server with PostgreSQL and Nginx:

Vagrant.configure("2") do |config|
        config.vm.box = "rhouinard/oracle-65-x64"
        config.vm.network :forwarded_port, guest:80, host:8000
        config.vm.provision :chef_solo do |chef|
            chef.add_recipe "postgresql::server"
            chef.add_recipe "postgresql::client"
            chef.add_recipe "nginx"
            chef.json.merge!({
                :postgresql => {
                    :password => {
                        :postgres => "idontlikerandompasswords"
                    },
                    :pg_hba => [{
                          :type => 'host',
                        :db => 'mydb',
                          :user => 'mydbuser',
                          :addr => '127.0.0.1/32',
                          :method => 'md5'
                    }]
                }
            })
        end
    end

This isn't the simplest example, but it shows us a sample of what we can do with Vagrant. Reading from the top, we see that we are declaring a "box" or target VM: RHEL 6.5. Vagrant will fetch this box from its own cloud provider (Vagrant Cloud), a network file system, or another URL, and work with VirtualBox automatically to stand it up. Next in the example, we forward activity from the host's (your development machine) port 8000 to the guest VM on port 80, which allows us to run a web server listening on port 80 inside the VM, but test it by hitting port 8000 on our host system. At this point you may be asking what good this does, because isn't our code stuck on the host machine? Actually, Vagrant gives us the root folder of the project as a network share inside the VM. So, the web server in the VM can execute project code, but we still have control over it in the development environment on the host.

That is Vagrant in a nutshell. But, don't forget the chef-solo provisioner block, which ultimately gives us 100 percent parity with our test and production environments. We don't need to worry about running chef as a provisioner--Vagrant will do that for us. As developers, we just need to work with the operations team to make sure this configuration is accurate and fulfills the requirements.

How does it all work?

The following command will kick off the entire process, and at the end, you will have a running, provisioned VM:

$ vagrant up

This command will start a secure shell on the VM:

$ vagrant ssh

There are many other Vagrant commands to reprovision, suspend, resume, and restart the VM, as well as manage the Vagrant boxes themselves. For example, you could preconfigure a VM for the team if there is a special requirement, repackage that VM as a custom Vagrant box, and distribute it on a network share. In this case, config.vm.box would look something like:

config.vm.box = "http://file-share/vagrant-boxes/oracle-65-x64.box"

Vagrant works with VirtualBox, but it also works with VMware Fusion or Workstation, and with some finagling can even stand up and provision VMs on an ESX host.

Every two weeks, the SEI will publish a new blog post that will offer guidelines and practical advice to organizations seeking to adopt DevOps in practice. We welcome your feedback on this series, as well as suggestions for future content. Please leave feedback in the comments section below.

Additional Resources

To read all the installments in our weekly DevOps series, please click here.

About the Author