Virtualized Development Environments with Vagrant
Saturday, October 29, 2016 2016-10-29 19:40

Virtualized Development Environments with Vagrant

Virtualized Development Environments with Vagrant

If you have been developing computer software as a member of a team, you have probably encountered a situation that a project does not work as expected for you, while another member of the team simply tells you: "it works on my machine". This is quite a frustrating problem because there are many moving parts in a modern computer system and then you would be on your own trying to find the culprit. Different machine architectures, hardware components, Operating systems, installed set of software and configuration parameters are some of the things you have to look into.  


While trying to avoid this scenario in future, you might say let's create a specific virtual machine, include everything needed for this project and share it with others. Virtual machine technology (or containers, for that matter) allows us to take care of most of this issues. But there are two problems which need to be solved before virtual machines could become practical. First sharing an entire virtual machine disk image, configuration and all future modifications among team members (which could span across the world, by the way) and second automating virtual machine lifecycle and keeping track of the all the changes that have been made to this machine by any team member. You could be a system administration wizard and suggest using a virtual machine abstration and automation software like `libvirt` and putting a configuration management software like Puppet or Salt on top to configure the software on the machine. But this is way more complex and time consuming than a developer would like.  


Enter Vagrant

Vagrant is a tool for building and distributing virtualized development environments. It provides the framework and configuration format to create and manage complete portable development environments. These development environments can run locally as a virtual machine or container or in the cloud via AWS or OpenStack, and are portable between Windows, Mac OS X, and Linux. Vagrant is in no way a production-level software deployment tool and does not try to be. It is a tool to be used by developers administrators or designers while still working in test and develop stage and need to isolate their work from their host system or share their project environment with others. The goal of vagrant is to make this process as simple, transparent, portable and automatic as possible.


The basic vagrant configuration is based in one file, the `Vagrantfile`. It shall be placed in your repository root. In this file you will define which base box you want to be run in your virtual machine. Although `Vagrantfile` is a Ruby file, all Vagrant configuration is done by simple variable assignments inside it and most likely won't need Ruby knowledge. Below is how the very basic VagrantFile looks like:


Vagrant.configure("2") do |config| = "debian/jessie64"

Instead of building a virtual machine from scratch, which would be a slow and tedious process, Vagrant uses a base image to quickly clone a virtual machine. These base images are known as "boxes" in Vagrant, and specifying the box to use for your Vagrant environment is always the first step after creating a new Vagrantfile. Boxes are stored under a specific name so that multiple Vagrant environments can re-use them. While it is easiest to download boxes from HashiCorp's Atlas (the default), you can also add boxes from a local file, custom URL, etc. Boxes can be created from any OS of your choice by manually creating the machine under a specific virtualization provider and following a series of steps to make it compatible with vagrant's expected format. Boxes are added to Vagrant with `vagrant box add`.


This is a usual vagrant workflow:

 Create a vagrant machine (debian jessie 64 bit in this case): `vagrant init debian/jessie64` `vagrant up` The above command will also trigger Vagrant to download the requested box via the specified URL. Vagrant only does this if it detects that the box doesn't already exist on your system. Login to the created machine: `vagrant ssh` key-basedi ssh authentication have already been setup for this machine, so you are instantly in and the user you are logged in as --`vagrant`, has `sudo` priviledges with no password.

Stop the machine after your work is done. use either `vagrant halt` to turn off or `vagrant suspend` to pause the machine. Use `vagrant up` or `vagrant resume` respectively to start the machine again. Use `vagrant status` to see current machine status. Note that suspend operation takes up some additional disk space than machine disk alone, in order to store the contents of machine RAM. Instead the machine comes up faster and the entirty of previous machine state will be restored.

You can "reset" the vagrant box with `vagrant destroy`. This will turn back the box to the default configuration of the initial box. Everything you installed or configured in this machine after the very first `vagrant up` command will be lost forever. The `vagrant destroy` command does not remove the downloaded box file. To completely remove the box file and free up some space, you can use the  `vagrant box remove` command. Vagrant boxes also get automatically updated from their upstream as soon as box updates are released, so developer does not have to worry about OS updates. 

Although this is all you need to know to get a basic use out of vagrant, here are a list of more features offered: 

Vagrant will automatically sync your files to and from the guest machine using "synced folders". By default, Vagrant shares your project directory (that is the one with the `Vagrantfile`) to the `/vagrant` directory in your guest machine. This share is read/write and you can continue working on your project from inside the vm.

Vagrant has built-in support for automated provisioning. Using this feature, Vagrant will automatically execute configuration commands when you `vagrant up` so that the guest machine can be repeatedly created and be instantly ready to use. Although `shell` provisioner should be enough for most projects (i.e. shell commands or scripts will be executed on vm automatically just after vm is created and brought up), Vagrant also supports integration with all popular configuration management systems like Puppet or Salt.

Vagrant supports several types of network connectivity with host system, public and/or private network and you can add as many network links as you need.

While Vagrant defaults to VirtualBox for virtualization, it can work with a wide variety of backend providers, such as VMware, Docker and more on a variety of host operating systems, and supports provider-specific configuration. Once you have a provider installed, you do not need to

make any modifications to your Vagrantfile, just `vagrant up` with the proper provider and Vagrant will do the rest: `vagrant up -- provider=vmware_fusion`

Vagrant is able to define and control multiple guest machines per Vagrantfile. This is known as a "multi-machine" environment. These machines are generally able to work together or are somehow associated with each other. For example this feature allows modeling a networked distributed system accurately. Each machine should be assigned a name, which distinguishes it from others when you need to run vagrant commands which target a specific machine. For example:`vagrant ssh db`

Vagrant supports creating powerful, first-class citizen plugins that extend Vagrant using a well-documented, stable API. In fact, most of the core of Vagrant is implemented using plugins.  

It is advisable to install vagrant from the latest packages made available on the website, rather than OS repositories, because this is a rather new and very actively developed project and you might face with issues if using old versions.



Head to where you can download Vagrant, read the excellent documentation, and search for vagrant boxes which have been built by the supporting company or the user community.