Why Vagrant? – Preventing Deployment Issues from Day One with a Virtual Machine

virtual-dev-environment

One of the traditional problems in software development is the delivery of a finished project. Atomic Object writes custom software, but we ultimately need to deliver it to our customers, which usually implies deploying it to an existing infrastructure environment, or handing it off to an operations team.

Unfortunately, this hand-off process often introduces a variety of glitches and bugs due to differences between the environment that the software was developed in (the development environment), and the environment it will actually run in (the production environment).

Vagrant is a tool for creating and configuring virtual machines. It provides an interface to easily bootstrap and manage virtual machines using a variety of different virtualization platforms and configuration management tools, both open source and commercial. By using Vagrant, developers can easily write and test applications in environments similar to which they will actually be deployed. This reduces the likelihood of glitches and bugs when handing off a finished project to customers.

How Development Actually Happens

Application development usually occurs on local developer machines. This makes the life of the developer easier: they have use of their own tools and customizations, and they can operate in comfortable surroundings. The setup is geared towards making the creation of the application as smooth as possible.

In contrast, deployed applications usually run in a fairly spartan server environment which often lacks a GUI (graphical user interface), customizations, and many convenience applications. Moreover, the server might be running a different operating system from the one that the application was actually developed on. The setup is intended to make running the application as smooth as possible.

This discrepancy, understandably, can be a source of problems. Code can behave differently on divergent environments. In some cases it can be as simple as a configuration difference (e.g. the default locale of a user environment is set to Latin-1 vs. UTF-8), and in others it can be as fundamental as a processor architecture difference (e.g. some required application dependency is available for 32-bit processors, but not 64-bit processors).

To complicate the situation, developers often do not have access to the final “production” environment on which the application will be deployed.

Enter: Vagrant

Vagrant allows developers to easily create and use environments much more similar to the target production runtime environment of their application without needing to leave the comforts of their own machine. While the virtualization capabilities underlying Vagrant are nothing new, Vagrant provides a common programmatic interface to bootstrap virtual machines in an rapid, reliable, and automatable fashion.

With such a tool, it’s easy to create, use, and tear down a virtual machine that is much more similar to an application’s target deployment environment than a developer’s own machine. Potential problems caused by differences in development and production environments can be identified and corrected sooner, increasing “dev/prod parity”. This reduces the risk of encountering bugs and incompatibilities upon application delivery.

How Does Vagrant Work?

Vagrant can be thought of a wrapper around existing virtualization technologies and platforms, including Oracle’s VirtualBox, VMWare’s Fusion, AWS, and several other platforms (both local and cloud-based). Once configured, a single set of commands (and API) can be used to create, access, and then destroy virtual machines.

Each instance of a virtual machine managed with Vagrant is a called a “Vagrant”, and many Vagrants can exist at once.

The actual operating system running on the virtual machine is loaded via Vagrant “box”, a portable file which includes a disk image and configuration information. Many “boxes” exist for a host of different operating systems and virtualization platforms, and it is possible to create new ones. Developers only need to find (or create) an appropriate Vagrant box to get started.

For example, a developer working on Mac OS X 10.9 may be writing a web application that will ultimately be deployed on CentOS 6.5, 64-bit. The developer just needs to find an appropriate Vagrant box for CentOS, download it, boot up the Vagrant, deploy the application to it, and start testing.

Such testing will likely result in some customization of the virtual machine (installing web servers, libraries, etc.) to get the application running. This allows the developer to identify and document dependencies and configuration changes early on — valuable information for an operations team who will later be responsible for running the application in the production environment.

After such customizations are made, Vagrant can re-package the virtual machine into a new Vagrant box. This box can be used as a new base to start new virtual machines, allowing the developer to work on tweaking and troubleshooting the application unhindered by concerns of keeping the virtual machine in a pristine or “production-like” state. If troubleshooting breaks the system, or causes a major configuration mess, the virtual machine can be tossed out, and a new one can be bootstrapped easily.

The developer can also share this new customized Vagrant box with other developers on the same project, extending to them the same access to an environment similar to the application’s target deployment environment.

The commands in a typical workflow might look like:

  • vagrant add to import an existing Vagrant box.
  • vagrant up to boot a Vagrant.
  • vagrant ssh to login and use a Vagrant.
  • vagrant halt to shutdown a Vagrant.
  • vagrant package to create a new Vagrant box.
  • vagrant destroy to delete a Vagrant.

Conclusion

Vagrant is a valuable tool for improving the quality of new applications. Developers can access and work with environments much more similar to the one that their application is supposed to run in, allowing many bugs and configuration issues to be identified and fixed earlier in the software development process. This clearly aids the developer, but also benefits the customer as they are exposed to less risk and uncertainty when their application finally gets delivered and goes to launch. The “works on my machine” excuse is no longer plausible or defensible as applications can now be created and tested readily in the environment in which they are expected to run.