Fork me on GitHub

Introduction to 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 the 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 these 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 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 abstraction and automation software like libvirt and putting a configuration management software like Puppet or Ansible 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-grade 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 the test and development 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|
      config.vm.box = "debian/jessie64"
    end

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 parlance, 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 the 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-based ssh authentication has already been set up for this machine, so you are instantly in and the user you are logged in as —vagrant, has sudo privileges 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 the 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 entirety of the 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 is a list of some more features offered by it:

  • 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 it is created and brought up), Vagrant also supports integration with all popular configuration management systems like Puppet or Ansible.
  • Vagrant supports several types of network connectivity with the 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 and predictably. 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 actively developed project and you might face some issues if an old version is being used.

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

Social