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