Packer Built CentOS Vagrant Base Box – Automated Build

I have been using Vagrant and Chef  to setup and maintain the development environment for the projects I work on. I have been pretty comfortable with Vagrant for a while now and have becoming increasingly more comfortable with Chef. However, one aspect of this process I hadn’t really dealt with before was building base boxes for Vagrant.

Admittedly, this is not something you have to do often if at all due to sites like and the Puppet and Bento base boxes. However, there have been times where I didn’t find quite the combination of OS and provisioner I was looking for. I decided it was time to sort out how to build the ever elusive base box.

Packer Vs. Veewee

I took a look at both Packer and Veewee. Veewee came with a recommendation from one of the OpsCode pages. Packer was just something that I remembered from lots of “Packer-built” messages in some of the base boxes I used in the past. The features of both are very similar. At the end of the day both systems can take a configuration file and get you to the point where you have a box suitable for import into Vagrant. I did find that I was having trouble getting Veewee to build a CentOs box and install Chef. Getting CentOS up and running was very simple. I just ran into strange dependency errors and issues with how it attempts to use sudo to install Chef. At the end of the day I wasn’t a huge fan of how it broke up the post install instructions. Once I get more comfortable with the process I am sure it would show its power. Instead I decided to give Packer a shot.

Installing Packer

Getting started with Packer is simple. The Packer documentation does a great job providing an overview. There is also detailed reference material once you get an understanding of what Packer is capable of. The installation of Packer just involves a zip file of several executables. If you have an unsupported OS you can also build it from source. I am using my trusty Mac for this example.

It is worth noting that the zip file contains all of the executables in the root of the zip file. This works well if you want to just dump all of the files in your bin directory or something like that. Just keep it in mind that unzip won’t be dropping the files in a separate folder unless you tell it to. Lastly, if you do not add the files to a directory already in the path, make sure you add that directory to your path.

A Basic Packer Build

Once packer is installed there is really just one configuration file that you need in order to get an install started. If you look through the Build an Image page they show you an example.json file that builds an AMI for use with AWS. I needed to build a VirtualBox image. My initial example.json file is shown below.

This was what I started with for getting an installed copy of CentOS using Virtualbox. The virtualbox-iso type is what tells Packer to spin up the image using VirtualBox. The iso_* keys instruct Packer where it can find the iso it should use to start up the virtual machine. You can provide multiple urls if you want to give Packer a couple of shots to download the file. You would just specify them as an array. It is important that they all point to the same iso. If the checksum provided doesn’t match the iso then Packer will abort.  The next two configurations set the username and password that are used to ssh into the image and finalize it once install is complete. I’ll touch on that more later. The last builder configuration is the command used to shutdown the vm when you are done. This will help ensure there is no loss of data. If it is not specified then VirtualBox will forcibly shutdown the box. This is a very basic configuration of a VirtualBox builder. You can look at Packer’s documentation of the VirtualBox Builder if you want a better understanding of the parameters.

The post-processors section tells Packer what it should do with the resulting VirtualBox files. We want to create a Vagrant box. This is all that is necessary for our post-processor. You can read Templates: Post Processors for more options.

Now that we have a configuration file I can fire up Packer and see what happens:

Packer is now going to download and verify the iso specified and will then spin up a VirtualBox vm with that iso.

Using Packer to create a CentOs Base Box for Vagrant

At this point, I now need to provide Packer with instructions on how to complete the install process. There is another configuration for Packer that lets you basically send keystrokes and waits into the vm: boot_command.

The boot_command parameter accepts an array of strings that will be interpreted as keystrokes. For alphanumeric characters you can just pass them straight into the string. You can also send special key sequences such as <enter> and <esc> to simulate the special keys. Finally you can use <wait>, <wait5>, or <wait10> to not send any keystrokes for 1, 5, or 10 seconds. So, you could at this point walk through the install process manually and add the keystrokes to the configuration file. However this will be very tedious and unreliable. If you attempt to build with you could find that you didn’t wait long enough. In order to fully automate this process you need to take advantage of your distribution’s unattended install functionality. For CentOS this functionality is referred to as kickstart.

Using Kickstart to Automate Installation

Kickstart forCentOS allows you to set up various installation parameters such as timezone, language, and disk configuration using a configuration file. The installer can then load this file over the network to complete the installation with no input required by you. Most distributions have this functionality under other names. Ubuntu and Debian call it preseeding, though they have another Kickstart like option as well.

Thankfully this is a common way for system administrators to perform installs so there is lots of documentation and examples. It was fairly trivial for me to find a kickstart example I could work with. I found a useful starting point for a kickstart file on github.

Setup Kickstart File

I put the kickstart in an http folder. This makes it very easy to access the file in our install process using packer. The contents of the http/kickstart file are below.

I am not going to get too deep into what this file is doing. There are however few things that I want to point out that are important to getting the iso to work with Vagrant.

This section makes sure sudo is set up in a way that passwords are not necessary to use sudo. This is not necessary but will make life down the road easier. It may not be the best thing to do for a production environment, but for a dev environment it’ll be okay.

These two sections create the vagrant user with the password we specified in the packer config and then takes care of getting the ever important Vagrant key set up.

At the end of the day, the only things you need to do in the kickstart file for packer to be able to work with it is:

  • Provide parameters necessary to properly install the OS.
  • Ensure the username and password specified in packer config are valid
  • Ensure that the shutdown_command and any provisioning commands are runnable.

Call Kickstart from Packer

Now, in order to make this kickstart file accessible by the install we can use the http_directory configuration option. This configuration does a couple of things. First, it takes the directory you specify and sets up an http server that serves this directory. Then it creates two variables: .HTTPIP and .HTTPPort. These can be used to access the server in your config file.

I set the http_directory configuration to http which is the directory I created the kickstart file in. Then using the boot_command configuration I send the keystrokes necessary to tell the CentOS install to use the kickstart file. In order to properly address the http server I used both the .HTTPIP and .HTTPPort parameters.

At this point we can rerun the packer build command with much more success.

This creates a Vagrant box ready for import.

Unfortunately this will result in some errors:

Vagrant is having trouble mounting its folders because we have not installed the guest additions for virtualbox.

Provisioning in Packer

Packer has the ability to provision after installation as well.  It provides much the same capability that Vagrant provides. You can use Chef, Puppet, shell or any mixture of them. To keep things simple I am just going to use the shell provisioner. I will use it to install both the guest additions, as well as Chef.

To add a provisioner to Packer, use the provisioner keyword.

By default, when using the virtualbox-iso builder, packer will upload the appropriate guest additions iso to the ssh_username‘s home folder. This allows the vm to easily mount the iso. I did find that I needed to install a slightly more specific version of kernel-devel than what VirtualBox instructs. Also, it is worth noting that Packer doesn’t remove the guest additions for you so I went ahead and deleted that myself. Finally, I install curl so I can run the Chef installation.

Now I can give the box another shot.

Testing the Chef install

Now I have a box I can ssh into. I can run a quick test to see if Chef is working properly. I will create a small test recipe to add the time the box was provisioned to my vagrant folder.

First I need to update my Vagrantfile to the following.

This runs a single test recipe via chef-solo.

This creates the test recipe and reloads and provisions the vm. I had to reload because the provisioner changed. After provisioning I have a file named provisioned with the current date and a time that is a few seconds old.

Wrap up

There are more things I still want to play with. I suspect there is still some dependencies I can cleanup after VirtualBox’s guest additions are installed. I also think I would be better off moving the installation of guest additions and Chef into the kickstart file’s %post section. I also know there are some configuration that would make it a bit more friendly for automation such as hiding the VirtualBox window. It is a good start though and it is good to have confidence that I can build base boxes when I can’t find one that suits my needs!

I committed all of the example files for this to my github account so if you want to fork it and play around feel free:

2 thoughts on “Packer Built CentOS Vagrant Base Box – Automated Build”

  1. Nice writeup. I was looking for an example of how the reboot command should be scripted in the provisioning section. Proved easy :-)

    I have kickstart , packer and vagrant running nicely with CentOS and Fedora. My headache at the moment: I’m having problems installing 32-bit libraries (one of the apps I want to run is 32-bit) without conflicting with the libs dkms needs.

  2. Leif – try installing the compatible version:

    yum install .i686

    Just substitute for the lib you need to install. You may also need to run:

    yum groupinstall “Compatibility libraries”

Leave a Reply

Your email address will not be published. Required fields are marked *