Running Vagrant Build on Jenkins

For my projects I make heavy use of Vagrant so that other developers can work in the same environment I am using. This also makes continious integration easier for your builds because you don't need to rely on a build machine becoming out of date or maintaining the correct packages, everything is managed in each VM.

This blogpost explains how I'm using Vagrant + Jenkins for continuous integration.

Jenkins Job

We don't use any of the Vagrant plugins for Jenkins (they seemed a little overkill) instead we just use this build script to boot up Vagrant and launch our build.

#!/usr/bin/env bash

vagrant up  
vagrant rsync  
vagrant provision

vagrant ssh -c "cd /vagrant; ./build.sh"  
result=$?

vagrant suspend

exit ${result}  

All that's really happening here is booting up the VM, provisioning it and then executing a build.sh script from the project (this can be your equivalent build or test script). The VM is suspended at the end of the job to make bringup faster during the next execution. The error code is saved from exectuing the build script and Jenkins can correctly mark the job as failing or passing.

Modifying Vagrantfile to Make Use of Jenkins Resources

If you have dedicated Linux machines that are running your Vagrant based builds this additional tip may be of interest. We have a pool of servers that have lots more memory than our typical devleopment environments. We want the Vagrant VMs to make use of all those resources when they are running on our Jenkins servers, but not on our development machines.

Because a Vagrantfile is a ruby script, we can modify the Vagrantfile to gather information about it's environment before building the VM.

One assumption made is that Jenkins will always be running Vagrant based jobs under the username jenkins. However, if your environment is different it should be easy to adapt, you just need a programatic way to determine you are running on Jenkins rather than a development machine.

The Vagrantfile basically checks what user is running the machine. If it is a user named jenkins it determines the number of CPUs and amount of memory on the machine and grows the VM accordingly. The VM is also uses rsync for sharing content rather than VirtualBox shared folders, which perform poorly.

# -*- mode: ruby -*-
# vi: set ft=ruby :

require 'etc'

Vagrant.configure(2) do |config|

  config.vm.box = "ubuntu/trusty64"

  if Etc.getlogin == "jenkins" then
    cpus = Etc.nprocessors - 1
    # Get total memory by calling "free" command and parsing output
    total_memory = %x(free -m).split(" ")[7].to_i
    memory = total_memory - 1024
    # Use rsync for syncing
    config.vm.synced_folder ".", "/vagrant", type: "rsync", rsync__exclude: ".git/"
  else
    memory = 1024
    cpus = 1
  end

  config.vm.provider "virtualbox" do |vb|
    vb.memory = memory
    vb.cpus = cpus
    vb.linked_clone = true
  end
end  

Overall, this is a pretty simple setup for Jenkins + Vagrant that doesn't rely on any plugins.

comments powered by Disqus