Vagrant tricks – Creating local baseboxes

In this blog post I am going to go over a useful trick that I have been using to minimize the time of provisioning a vagrant box. Basically what it is about is having two vagrant or more vagrant files in the project (depending on what you are doing) and a script that creates a vagrant box from one of the vagrant files, then use the box in the next one.

Example

We are going to setup a machine with some applications that takes some time to install (can be what ever). Then we are going to configure the installed applications after they are installed, that will be our second vagrant script. Our first vagrant file will be named Vagrantfile.Basebox and our main vagrant file will be named Vagrantfile.

Vagrantfile.Basebox

$centos_box = "centos/7"
Vagrant.configure(2) do |config|
  config.vm.define "basebox" do |basebox|
    basebox.vm.box = $centos_box
    basebox.ssh.insert_key = false
    basebox.vm.synced_folder ".", "/vagrant", type: "virtualbox"
    basebox.vm.provision :shell, path: "long-running-task.sh"
    # more provisioning if needed
  end
end

This will be the script that creates the base box. I chose centos because there is a little quirk that needs to be addressed ( addressed in the comments in the script )

create-basebox.sh

#!/usr/bin/env bash

BOX_NAME=hx/base-centos

TEST_IF_BOX_EXISTS=$(vagrant box list | grep $BOX_NAME)
if [ "$1" = "-f" ]; then
    TEST_IF_BOX_EXISTS=""
    vagrant box remove $BOX_NAME
    if [ "$?" -ne 0 ]; then
        echo "Could not remove box, check if you have running machines using the box"
        exit 1
    fi
fi
if [ "$TEST_IF_BOX_EXISTS" = "" ]; then
    echo "$BOX_NAME does not exist, creating $BOX_NAME"
    mv Vagrantfile Vagrantfile.tmp
    cp Vagrantfile.base.rb Vagrantfile
    vagrant up basebox
    vagrant halt basebox
    # Centos specific, if you are using a different distro,
    # the next couple of lines are not necessary 
    vagrant up basebox
    vagrant halt basebox
    VBOX_INSTANCE=$(vboxmanage list vms | grep -oP "${PWD##*/}_basebox_[0-9_]*")
    vagrant package --base $VBOX_INSTANCE --output base.box
    # Handle paths differently when using cygwin
    if $(pwd | grep -q cygdrive) ; then
      BOX_FILE_PATH=$(echo "$PWD" | sed -E 's/\/cygdrive\/([a-z])(.*)/file:\/\/\/\1:\2\/base.box/')
    else
      BOX_FILE_PATH=$(pwd | awk '{print "file:" $1 "/base.box"}')
    fi
    vagrant box add $BOX_NAME $BOX_FILE_PATH
    vagrant destroy -f
    # Removing the box some times fails because the file handle has not been 
    # released. So put a short sleep before the remove 
    sleep 3
    rm -f base.box
    rm Vagrantfile
    mv Vagrantfile.tmp Vagrantfile
    echo "Done creating $BOX_NAME"
else
    echo "$BOX_NAME exists, moving on..."
fi

Then we can use the base box in the our Vagrantfile.

Vagrantfile

$custom_box = "hx/base-centos"
Vagrant.configure(2) do |config|
  config.vm.define "custombox" do |custombox|
    custombox.vm.box = $custom_box
    custombox.ssh.insert_key = false
    custombox.vm.synced_folder ".", "/vagrant", type: "virtualbox"
    custombox.vm.provision :shell, path: "config-task.sh"
    # more provisioning if needed
  end
end

This way you can do the bulk of the work in the basebox, cutting down on the time that it takes to provision the boxes that build on top of it.

Usage

./create-basebox.sh
vagrant up

One thought on “Vagrant tricks – Creating local baseboxes

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s