I’ve recently stumbled upon Vagrant and I am really happy about this discovery. In this post I’m going to name some of the reasons why Vagrant is useful. At the end, I’m going to implement a small real-world example.
So let’s get started.
What is Vagrant
Vagrant is “a tool for building complete development environments”. It is used to create virtual machines in a consistent and repeatable way. Virtual machines are provisioned on top of chosen virtualization software, typically VirtualBox. When the virtual machine has started, it can be provisioned with tools like Chef or shell scripts. With automated provisioning you can spawn a new virtual machine in a matter of minutes, fully configured to your specific needs.
Don’t worry if this all sounds a bit fuzzy. Just continue reading and you’ll get it by the end of the post.
Why is Vagrant useful
Vagrant enables you to create new, clean, fully configured virtual machine in a matter of minutes. You can use this virtual environment to execute some experiments and then dispose of it, or you can reuse it as normal virtual machine for as long as you want. This is especially useful if you want to try something in an operating system that isn’t installed on your machine.
I’m a Mac OS X user, but I often need to do something in Linux. So I just spawn a new Ubuntu virtual machine via Vagrant. This VM will be preconfigured with all the essential tools I need to be productive, e.g. fully configured Vim, properly set up Ruby and Python, Git, etc. After some experimentation I can discard the VM if I dirtied it somehow, or keep it for the future experiments.
Vagrant also enables you to effortlessly share your environment with colleges. This is extremely useful for collaboration purposes, as now the whole team can develop or debug in the same environment.
You just need to share the
Vagrantfile (Vagrant’s configuration file) and
provisioning recipes. The
Vagrantfile is written in Ruby and the provisioning
recipes are usually scripts or programs as well. Therefore you can put the
whole environment under source control tool like Git.
First install one of the supported virtualization providers. I use VirtualBox. It is free and runs on all the major operating systems.
Next, choose the appropriate installer and run it to install Vagrant itself.
Vagrant is used from the command line. Here’s a short list of useful commands to get you started1:
vagrant init– initializes the current directory to be a Vagrant environment by creating an initial Vagrantfile
vagrant up– creates and configures guest machines according to your Vagrantfile
vagrant ssh– SSH into a running Vagrant machine and give you access to a shell
vagrant destroy– stops the running machine Vagrant is managing and destroys all resources that were created during the machine creation process
vagrant suspand– suspends the guest machine Vagrant is managing, rather than fully shutting it down or destroying it
vagrant provision– Runs any configured provisioners against the running Vagrant managed machine.
I’m going to show you how to use Vagrant in a real-world situation so you can get a better feel for Vagrant.
In this example I want to use Linux traffic-control tool tc to limit the outgoing traffic generated by a Python script. At the same time, I want to sustain the SSH connection. I need to set up the tc rules and test the setup. The problem is, if I misconfigure the tc, I won’t be able to SSH to that machine anymore. I’m also working on a Mac machine and that complicates things even further. Luckily, I can use Vagrant to solve all the problems.
The full source code for this example is available on github.
Note that Vagrant provides quite a few advanced configuration options that I’m not going to cover in this simple example. Those include: port forwarding and network configuration, VM CPU/Memory management, custom plugins, etc.
New Vagrant environment
To get started, create a new directory, e.g.
initialize new Vagrant environment:
1 2 3
vagrant init command creates the
Vagrantfile. This is the Vagrant
configuration file, written in Ruby. It contains lots of configuration
possibilities in the comments, so take a look around.
Next, you need to select a ‘base box’. The base box is a virtual machine image you want to use as base for your environment.
Although you could build a base box yourself, it’s much easier to use one of the publicly available boxes.
I’ve decided to use the Ubuntu Precise image from ubuntu.com.
Modify the configuration file to use this image:
1 2 3 4 5 6 7
box attribute is used to identify the image on the local system. Since
the box doesn’t exist yet, you are free to name the image however you want. The
box_url attribute specifies the download URL for the image.
With this you have the minimal settings needed to start the new Vagrant VM. You can do this by running:
If you get the warning that “The guest additions on this VM do not match the installed version of VirtualBox!”, just ignore it.
Now that the VM is up and running, you can log into it by running:
Congratulation, you are inside of a Vagrant VM.
Provisioning with Bash script
Now it’s time to provision the VM with chosen tc settings.
Create a new Python script, called
attack.py, to generate the egress traffic:
1 2 3 4 5 6 7 8 9
The script implements simple UDP flooding. To prevent the flooding, I’m going to use the following tc rules:
1 2 3 4 5 6 7
Without going too deeply into workings of traffic-control tool tc, those rules limit total outgoing traffic to 10kb/s (80kbit/s). The traffic is shared between two cgroups and the fairness is enforced. This prevents flooding from interfering with the SSH connection to VM.
Those rules need to be incorporated into the provisioning process of the VM.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Embedded provisioning shell script installs all the necessary tools and creates
the tc rules. It starts automatically the
attack.py script and places it into
a separate cgroup.
If you take a closer look, you’ll see that the Python script is invoked from
/vagrant/attack.py. This works because by default, the project directory (the
one with the
Vagrantfile) is shared with the VM at
/vagrant. You can also
configure shared directories explicitly if you want.
Now you can provision the VM:
(You can also start from scratch, by destroying the VM and starting it again
vagrant destroy and
You can safely ignore warnings like “stdin: is not a tty” or “dpkg-preconfigure: unable to re-open stdin: No such file or directory”.
SSH again into the VM and check that the setup is in place and working:
You should see something like:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Class 2:2 (
attack.py script) should generate traffic faster than class 2:1
(system traffic, in this case mostly SSH connection traffic).
You can play around with tc rules and provisioning process, e.g. you can remove the tc rules and start the flooding script to see your SSH connection being flooded and terminated.
That’s all for this simple example. The example itself is not really important. Instead, you should get the feeling of how easy to use and useful Vagrant is.
Vagrant is tool for managing different development environments. You can use it to experiment or develop in customised VMs. You can also used it to share the environment with your colleges.
Check out the “Vagrant: development environment” post for details on how I’m using Vagrant to set up my personal, on-demand, Linux development environment. In Using Thoughtworks’ Go (Continuous Delivery) With Vagrant you can see how easy it is to use Vagrant to explore and try out new software.
If you use Vagrant in an innovative way or just want to chat about it, send me an email.
All the descriptions are taken from the official documentation.↩