I’ve recently been looking into Vagrant. Vagrant allows you to build virtual environments and easily distribute them. By pragmatically describing virtual environment it easily allows developers to share configuration during development, and also eases the pain of setting systems up for distribution.

I recently worked on a project which proved quite complex to deploy. Not only did the project require different components from a variety of sources but the components were subject to change throughout the development process. Every time the versions changed all the developers had to modify their setup. If we started using a tool such as Vagrant it would have allowed us to share the same system setup thanks to the re-use of a virtual machine.

Vagrant is built upon VirtualBox by Oracle. You’ll need to ensure that you have the non-free version of this installed.

Vagrant works by applying recipes to a box. A box is a virtual machine which has been configured to allow Vagrant to access it. Recipes are combination of Ruby scripts which allow you to configure the box. When you run vagrant up the recipes are applied to the box.

You can download a generic Ubuntu Hardy Heron box from the Vagrant site:

vagrant box add base http://files.vagrantup.com/base.box

You only really need to create recipes for the software specific to your project. Thanks to Vagrant being based on Chef there are already quite a few recipes available. When setting up your project it’s worth creating a submodule containing existing recipes and separate folder for your own customisations.

If found the following snippet of code on the Chef wiki which will allow you to do this using Git:

mkdir my-project
cd my-project
git init
git submodule add git://github.com/opscode/cookbooks.git ./cookbooks
git add .gitmodules cookbooks/
git commit -m "Import Opscode pre-made cookbooks"
mkdir site-cookbooks/vagrant_main/recipes -p
touch site-cookbooks/vagrant_main/recipes/default.rb
git commit -a -m "Added blank default recipe"

Any customisations can then be placed within site-cookbooks.

The vagrant_main recipe is the first recipe run. If you want to run any of the other recipes you’ll need to include it within vagrant_main/recipes/default.rb.

Vagrant reads it’s options from a Vagrantfile. To create a basic Vagrantfile you can use the vagrant init command. In the Vagrant file you specify which box you are using and how the machine is provisioned. In my Vagrant file I have the following:

config.vm.box = "debian-testing"
config.vm.provisioner = :chef_solo
config.chef.cookbooks_path = ["cookbooks", "site-cookbooks"]
config.vm.forward_port("web", 80, 4567)
config.chef.log_level = :debug
config.vm.boot_mode = "gui"

config.vm.box specifies that I’m not using the Hardy Heron box, but a box I have created based on Debian testing.

config.vm.provisioner specifies that I’m using Chef Solo. Chef Solo reads recipes from my local machine. Chef also allows you to store recipes on a remote repository, this is called Chef Server. Vagrant will also allow you to provision boxes by running a shell script.

config.chef.cookbooks_path is a list of folders which contain the recipes. I’ve set these to be my Git submodule and my local customisations.

config.vm.forward_port specifies which ports will be forwarded. My machine will be a web server, so I’m forwarding requests from my local port 4567 to the virtual machines port 80.

The last two options are only for my debugging. config.chef.log_level allows you to run Chef in debug mode. config.vm.boot_mode pops up the VirtualBox display. By default the virtualbox display is hidden, enabling this option allows you to see if any errors are occurring during boot up.

Debian Testing

One of the projects I am working on uses CouchDB 0.11. Unfortunately there’s not yet a package for the latest version of Ubuntu. I could install it from source, but this would lead to a rather complicated recipe. I opted for using a Debian testing box. Debian testing has a packaged version of CouchDB 0.11.

Unfortunately a Debian testing box for Vagrant is not publicly available. It probably wouldn’t be a good idea either - Debian testing is only for testing. I set about creating my own box for the purpose.

Create a virtual machine

Download the latest minimal ISO image from the Debian mirrors and create a new virtual machine. Follow the guidelines specified in the Vagrant documentation when deciding sizes and user accounts.

Setting administrator privileges

 su

Add “vagrant” to the adm group

nano /etc/group

Install and configure ‘sudo’

apt-get install sudo
visudo

Add the following line

%adm ALL=NOPASSWD: ALL

Configure Grub

Ensure that when you boot up that the default Kernel is not ‘trunk’, otherwise you will not be able to install the Linux headers. Do this by modifying the Grub configuration file.

sudo nano /boot/grub/grub.cfg

Find the set timeout=5 and replace it with set timeout=1. This removes the delay in boot up.

Also you can remove the un-used menu entries. I only have one menuentry for Debian GNU/Linux, with Linux 2.6.32-3-686 - the others are commented out.

You can find more information on configuring the Grub menu in the Grub Manual

VirtualBox additions

Install the Linux headers and build tools:

sudo apt-get install linux-headers-2.6-686 build-essential

Mount the Guest Additions from the virtual CD ROM.

sudo mount /media/cdrom
sudo sh /cdrom/VBoxLinuxAdditions-x86.run

Restart the machine to apply the changes

sudo shutdown -r now

Vagrant dependencies

Install Ruby

sudo apt-get install ruby ruby-dev libopenssl-ruby rubygems

Install Chef

sudo gem install chef

When Vagrant provisions your virtual machine it will run chef-solo. This executable will need to be available to the sudo command. You can either create a symbolic link from the /usr/local/bin folder or modify the sudoers file:

sudo visudo

Append the following line:

Defaults secure_path="/bin:/usr/bin:/usr/local/bin:/var/lib/gems/1.8/bin"

Network interfaces

Ensure that eth0 is configured automatically

sudo nano /etc/network/interfaces

Ensure you have the following lines

iface eth0 inet dhcp
auto eth0

If you have any problems connecting to the VirtualBox then remove the persistent udev rules. You will also have to do this if you move your virtual hard disk between machines.

sudo rm /etc/udev/rules.d/70-persistent-net.rules

You can read more about this in the VirtualBox bug report.

Creating the package

Once you are happy with the box remove any temporary files. Keeping the size of the virtual machine will help if and when you want to distribute it.

Now create a Vagrant box by executing the following command:

vagrant package --base debian-testing-base

Replace debian-testing-base with the name of your virtual machine. This will create a package.box in the current directory. You now need to import this package:

vagrant box add debian-testing package.box