Saving the environment with Vagrant

I've been playing a bit with Vagrant, an easy way to set up virtual machines for development purposes. Vagrant provides a simple command line interface paired with a setup script (VagrantFile) in Ruby to provision virtual machines, share folders between the host and the virtual machine and to provide port forwarding. I've been using it to set up some Linux development environments on Windows, as well as just for keeping my development machine clean, and running different versions of otherwise incompatible packages/gems.

To illustrate how easy Vagrant makes this process, let us set up a Solr development environment. After downloading and installing Vagrant, we can initialise a project with the init command :

$ vagrant init

This command creates a VagrantFile with some Ruby code in it that acts as configuration for your virtual machine. Vagrant builds a virtual machine from a base box. A list of publicly available boxes can be found here. For this machine, we can base it on the Ubuntu Lucid 32 bit image:

# -*- mode: ruby -*-
# vi: set ft=ruby : do |config| = "lucid32"
  config.vm.box_url = ""

That's all you need for a complete virtual machine. Running the up command will create and initialise it:

$ vagrant up

[default] Importing base box 'lucid32'...
[default] Matching MAC address for NAT networking...
[default] Clearing any previously set forwarded ports...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- v-root: /vagrant


Vagrant imported the hard drives from an existing box in my profile - if you have not downloaded the lucid32 box before, it will happen on initialisation.

Note the port forwarding bit in the snippet above. Vagrant makes it easy to forward network traffic from a port on the host to one on the virtual machine - by default it will create a forwarding port 2222 to forward traffic to SSH port 22. On operating systems that come with SSH, Vagrant can open an SSH session to the box by using the ssh command:

$ vagrant ssh

Unfortunately, since SSH is not shipped with Windows out of the box, the ssh command is not available on that platform:

`vagrant ssh` isn't available on the Windows platform. You are still able
to SSH into the virtual machine if you get a Windows SSH client (such as
PuTTY). The authentication information is shown below:

Port: 2222
Username: vagrant
Private key: C:/Users/[user]/.vagrant.d/insecure_private_key

Windows users can use Putty (or any other SSH client) to connect to the virtual machine with the private key provided. Vagrant automatically shares the current folder between the host and the virtual machine:

[email protected]:~$ cd /vagrant/
[email protected]:/vagrant$ ls
[email protected]:/vagrant$

We now have a functional Ubuntu machine with sudo access to it, but we still need to customize it for our development purposes. Vagrant integrates nicely with Puppet and Chef to install additional software and to manage it. In the enterprise this could be integrated nicely with your existing Puppet or Chef infrastructure, enabling you to easily create a clone of your production environment. In this example we'll use Puppet to set up Solr running in a Tomcat container. We'll create a directory called "modules" to hold pre-developed puppet modules, and a directory called "manifests" to hold our manifest. We need to point Vagrant to the manifest and the modules directory.

config.vm.provision :puppet do |puppet|
  puppet.manifests_path = "manifests"
  puppet.manifest_file = "solr_tomcat.pp"
  puppet.module_path = "modules"

We need to ensure a package refresh (aka apt-get update) to install the solr-tomcat package - there's a good example of how to do that here. After we've added the package dependency, our manifest file looks like this:

class apt {
  exec { "apt-update":
    command => "/usr/bin/apt-get update"

  # Ensure apt is setup before running apt-get update
  Apt::Key <| |> -> Exec["apt-update"]
  Apt::Source <| |> -> Exec["apt-update"]

  # Ensure apt-get update has been run before installing any packages
  Exec["apt-update"] -> Package <| |>

package { 'solr-tomcat':
  ensure => present,

vagrant reload will reboot our machine and apply the configuration, and we should have Tomcat installed with Solr running on top of it. By adding the following line to our VagrantFile, we can get Vagrant to forward all communication from our local port 8181 on the host to the VM port 8080 where Tomcat is listening:

config.vm.forward_port 8080, 8181

When you go to http://localhost:8181/solr/ in your local browser, you should now see Solr up and running, congratulations! Now all that's left is to share some files between the guest and host operating systems, specifically the configuration files in /etc/solr/conf. Vagrant shares the project folder with the guest OS by default under the directory /vagrant. Let's start by copying the files we want to the host machine.

cd /etc/solr/conf/
mkdir /vagrant/solr
cp -R * /vagrant/solr

Once we have the files locally, we can mount this local directory over the one in the VM by adding this line to the VagrantFile :

config.vm.share_folder "solr", "/etc/solr/conf", "solr"

You can reload the virtual machine by running vagrant reload. You are now able to do some Solr development while maintaining a clean running environment for your indexes. Best of all, you should now be able to reproduce the environment reliably, so you can feel free to experiment.

Photo by Katy Belcher on Unsplash