Using Packer & Vagrant to bootstrap a testing infrastructure (Part 1)

Imagine you have an IT infrastructure that is managed by configuration management systems like SaltStack, Chef, Ansible, Puppet or others. The state of resources like running Unix daemons, files with specific contents and a list of users that should be present on all systems are defined in code (Infrastructure as Code). A version control system like Git is used to store this code. The systems that check this Git repository out take care of configuration rollouts and remote execution commands in the infrastructure.

To add a change to your systems the following workflow is used:

  1. Retrieve the current version of code
  2. Add changes to the code
  3. Upload (a.k.a. commit and push) the new version of code
  4. Trigger your tools to add the change in the infrastructure

Every time you plan to change parts of your infrastructure you need to go through the whole workflow.

It can be useful to test changes before they are committed, e.g. to save time and prevent creating a lot of unneeded commits with meaningless commit messages. For this you can create virtual machines on your local workstation that are very similar to the systems in the production environment and doesn't cost you expensive Enterprise hardware resources.


A tool that helps you managing VM images is Packer. Because keeping VM images up to date can be time consuming, Packer helps you to create consistently identical images fully automatically. As soon as you have configured a VM template to your needs the only thing you have to do is to run Packer with appropriate command-line arguments. Packer downloads the install ISO image, creates a VM using your desired hypervisor (VirtualBox, Libvirt/ QEMU, VMware Fusion), installs the operating system, shuts the VM down and creates an image file from the VM disk.

Now you can use this VM image as base for new VMs. You tell your hypervisor to create a VM with 2 virtual CPU cores, 2048 MB RAM, network interfaces, shared folder of your code that will be available to your VM and set a copy of your freshly created image as disk file.
At this point we are able to create new VMs that have the same state of an operating system installed. To run our test utilities or to test changes using our configuration management tools we need to prepare the following tools in our VM:

  1. Set SSH port-forwarding on NAT interfaces so can we log into the VM via SSH
  2. Set a system hostname
  3. Set NIC configuration (MAC/IP/subnet/gateway address)
  4. Install testing tools
  5. Deploy code and testing configuration

Since we want to test code that brings new bug fixes or features in newly created test environments, we are going to go through this process very often. Can we reduce the amount of work or can we automate it? YES!

Say hello to Vagrant, which is is a tool to create and configure lightweight, reproducible, and portable development environments or in other words: A tool to solve loads of problems. Vagrant takes care of all the steps described in the list above. It runs on GNU/ Linux, MAC OS and Windows due to the fact it requires a Ruby interpreter only.

Vagrant integrates with VirtualBox, some VMware products, Hyper-V and Libvirt (providers). It provides a Ruby API to manage resources and properties of VMs. You tell Vagrant which VM image (box) to use and which steps should be taken to install and prepare software in the VM (provisioners). As soon as your Vagrant VM is defined using the Ruby API in a text file called Vagrantfile, you run vagrant up and Vagrant does the rest for you.

To sum it up:

Packer helps you to create VM images (boxes). Vagrant is a tool that acts as a high-level VM platform manager which makes use of Packer boxes to create and manage new VMs.

So you're interested? In the next part of this blog post series I'm going to show how I create boxes using Packer.

Watch out for new blog posts or take a look at the documentation of Packer and Vagrant for a quick start.