Vagrant recreates a development virtual machine from a text file: vagrant up reads a Vagrantfile, downloads a base image, configures networking and shared folders, runs the provisioning scripts, and leaves behind a VM reachable over vagrant ssh. The same file, committed to the repository, gives the same environment on every machine in the team. Version 1.1.0 is out today, 14 March 2013 (CHANGELOG).

Context

When one developer’s environment does not match another’s — or production’s — the cost comes back every cycle. Different interpreter versions, a missing system library, a daemon configured by hand two years ago and never documented: put together, these differences produce the classic case where the code runs on one machine and breaks on the next, with the cause showing up nowhere in the repository.

The usual answers are two, and neither is enough. The setup document — the README listing the packages to install — goes stale the moment someone updates their environment and forgets to update the text. The shared staging box centralises configuration but brings contention back: one change breaks everyone’s work.

Vagrant, written by Mitchell Hashimoto and having reached 1.0 on 14 March 2012 (Wikipedia), brings the configuration into the repository and makes it executable. The environment stops being a procedure to follow and becomes an artefact rebuilt from scratch with one command.

Architecture

The Vagrantfile is Ruby code with a declarative DSL. A minimal example:

Vagrant.configure("2") do |config|
  config.vm.box = "precise64"
  config.vm.network :private_network, ip: "192.168.33.10"
  config.vm.synced_folder ".", "/vagrant"

  config.vm.provision :shell, path: "setup.sh"
end

The "2" string passed to configure denotes the configuration format version, not the Vagrant version: 1.1.0 introduces this schema while leaving readable the Vagrantfiles written for 1.0.x that use no plugins (CHANGELOG).

config.vm.box names the base image — a box, that is a ready-made VM exported in a format Vagrant can import. synced_folder mounts the host’s project directory inside the VM, so editing stays on the host and execution happens in the isolated environment. provision wires up the configuration step: a shell, or one of the supported configuration management systems (Puppet, Chef, Ansible, Salt).

The lifecycle runs on a handful of commands: vagrant up creates and starts, vagrant ssh opens a shell, vagrant reload reapplies the configuration, vagrant halt stops, vagrant destroy deletes the VM and leaves the Vagrantfile untouched. Destruction is the interesting primitive: rebuilding the environment from scratch becomes an ordinary operation, not an accident to avoid.

The critical point: providers and plugins

Through 1.0.x, Vagrant ran on VirtualBox only. The 1.1.0 release introduces the provider system: the workflow (up, ssh, provision, destroy) is decoupled from the virtualisation engine that carries it out. VirtualBox stays the default provider, free of charge; other backends are added as plugins, installable with vagrant plugin install (CHANGELOG).

HashiCorp’s first alternative backend is the AWS provider, shipped as an MIT-licensed plugin alongside 1.1.0 (HashiCorp, Preview: Vagrant AWS Provider). With the same Vagrantfile — provider specifics aside — you start an EC2 instance instead of a local VM:

vagrant up --provider=aws

The practical consequence is clean-cut. The Vagrantfile describes what the environment must be — packages, networking, provisioning — and leaves to the provider where it is materialised. The same descriptor applies to the VM on the laptop and to the cloud instance, as long as the box and the provisioning hold on both backends.

Plugins are Ruby gems with a hook point Vagrant knows about. The 1.1.0 release manages them from the vagrant plugin interface and states the intent of keeping them loadable in later versions too (CHANGELOG). The 1.0.x Vagrantfiles that used plugins must be cleaned up before upgrading; those without plugins stay compatible.

Implications

Provisioning is where Vagrant meets configuration management. A shell script is enough for simple cases; for environments that reproduce production, the same tool already in place there is the better choice. If production runs on Puppet, the same manifests provision the development VM, and the local environment inherits production’s configuration choices rather than approximating them by hand. Vagrant forces no choice: it stays the glue between the machine descriptor and the configuration tool, whichever it is.

Then there is versioning. Keeping the Vagrantfile under version control means the environment’s history coincides with the code’s history: a commit that adds a system dependency touches the Vagrantfile in the same changeset that touches the code. Whoever runs git pull and vagrant reload ends up with the updated environment and no out-of-band instructions.

In this same period another way to isolate has turned up. Docker, presented publicly this month (dotCloud), ships containers that share the host kernel: lighter than a VM, but bound to compatibility with that kernel. Vagrant works at a different level — a full virtual machine, with its own kernel — and the two tools cover distinct needs: a container does not replace the VM when you need to test on an operating system different from the host’s.

Limits

A full VM costs. Starting one takes RAM and a boot time measured in tens of seconds; a project with several services on separate VMs saturates a laptop quickly. Where isolating the filesystem and processes is enough, the weight of a VM is disproportionate.

Box distribution, as of 14 March 2013, is still hand-rolled: boxes sit on HTTP servers referenced by URL, with no public registry to vouch for their provenance and version. Reproducibility depends on those URLs staying stable and the images staying immutable, two guarantees nobody offers in explicit form today.

The provider system is brand new. The 1.1.0 CHANGELOG explicitly calls it groundwork, with changes expected throughout the 1.x cycle. Writing a Vagrantfile today that depends on a provider other than VirtualBox means reckoning with an interface that may move in nearby versions.


https://github.com/hashicorp/vagrant/blob/v1.1.0/CHANGELOG.md https://www.hashicorp.com/blog/preview-vagrant-aws-provider https://en.wikipedia.org/wiki/Vagrant_(software) https://www.docker.com/ https://www.noze.it/en/insights/vagrant-dev-environments/

Cover image: Mitchell Hashimoto, the author of Vagrant, speaking at a microphone during a talk at the RuPy 2012 conference — photo by Nils Pascal Illenseer, CC BY 3.0 — https://commons.wikimedia.org/wiki/File:Rupy_Talk_Mitchell_Hashimoto_(18945835).jpeg