Creating a CentOS 6.2 Base Box for Vagrant 1.1

Published 2013-04-14

In order to use vagrant you need something called a base box. When you run vagrant up, vagrant makes a copy of your base box to use with your project.

Mitchell Hashimoto (vagrant's author) provides an example base box based on Ubuntu, but I use CentOS at my workplace, so I've rolled my own base boxes. This walkthrough explains how to create a base box for Vagrant 1.1 using CentOS 6.2.

There are some automated tools you can use to do this, but I wanted to understand how all of the pieces fit together, because I feel less nervous about putting ssh keys and passwords into boxes that way, and I'm also better situated to troubleshoot when things go wrong (and they will).

However, once you've digested this article you might want to check out veewee and bento. At the very least, I'm sure you can improve on my process.

Before We Begin

You should have Vagrant 1.1 and VirtualBox and/or VMware Fusion Professional 5 installed. You can verify the version of vagrant via:

$ vagrant -v
Vagrant version 1.1.5

Also, all of the networking for vagrant requires your base box to use NAT ("Share with my Mac" in VMware). This is the default for VirtualBox and VMware, but if you've changed this somehow make sure your new boxes are created with the proper settings.

Configuring the System

Minimal Install

I started out with a cent 6.2 minimal image. It has a few quirks (which we'll work through below) but it also produces a very small base box size with little effort. Smaller boxes are faster to download and clone, so your iteration loop will be faster overall. Our target boxes will end up around 400-500 mb each.

Networking

The Cent 6.2 minimal install does not enable networking by default. If you want to connect to the internet (you do want to connect to the internet), you'll need to turn it on.

The default connection is located in:

/etc/sysconfig/network-scripts/ifcfg-eth0

If you open this with vi you'll notice the configuration says ONBOOT="no", which means this connection won't be started at boot time. This is obviously not what we want so we'll need to change a few things in this configuration to get the networking to start up:

DEVICE="eth0"
NM_CONTROLLED="no"
ONBOOT="yes"
BOOTPROTO="dhcp"

Make sure you remove the HWADDR line. This specifies that the config file should only be used on a device with a matching mac address. Since the VM manager will reinitialize the NIC when you clone the VM, the mac will change and the config will stop working.

Next, we also need to modify /etc/udev/rules.d/70-persistent-net.rules since it contains a reference to the mac address, too. Replace the eth0 line with:

SUBSYSTEM=="net", ACTION=="add", DRIVERS="?*", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

At this point, you can restart your system with shutdown -r now. When the vm comes back up your network connection will activate. You can verify your network connection is working by pinging something from inside the vm, e.g.:

$ ping google.com

If the command hangs or says there's a timeout, you have a problem. Press Ctrl+C to interrupt the ping command and troubleshoot (i.e. go google things).

Install VMWare Tools

Note: for VirtualBox, see the next section.

From VMware's Virtual Machine menu, Install VMware Tools. Then hop into the VM and mount the VMware tools CD.

$ mkdir /media/cdrom
$ mount /dev/cdrom /media/cdrom
mount: block device /dev/sr0 is write-protected, mounting read-only

Next, we'll need to extract and install the vmware tools (after typing VM, below, press the tab key to autocomplete the rest of it, since your version will probably be different):

$ cd /tmp
$ tar -xzf /media/cdrom/VM[tab].tar.gz
$ yum install -y perl
$ /tmp/vmware-tools-distrib/vmware-install.pl --default

Finally, let's unmount and do a bit of cleanup:

$ umount /dev/cdrom
$ rm -rf /tmp/*

Install the Virtual Box Guest Additions

If you're creating a box for VirtualBox, use this process instead.

In order to install the VirtualBox guest additions for doing fun stuff like mounting devices inside the guest OS, you'll need to install a kernel module. This requires the kernel source, so let's start by updating those:

$ yum update kernel* -u
$ shutdown -r now

From the Devices menu, click Install Guest Additions, which will attach the Guest Additions iso to the VM. If you need to access the iso directly, it's located in /Applications/VirtualBox.app/Contents/Resources/VirtualBoxVM.app/Contents/MacOS/VBoxGuestAdditions.iso after you install VirtualBox. Next:

$ mkdir /media/cdrom
$ mount /dev/cdrom /media/cdrom
mount: block device /dev/sr0 is write-protected, mounting read-only

Now that the image is mounted, we need to install a few tools and run the installer:

$ export KERN_DIR=/usr/src/kernels/`uname -r`
$ yum install -y gcc make perl kernel-devel kernel-headers
$ /media/cdrom/VBoxLinuxAdditions.run --nox11

Note: Some of the steps like OpenGL will fail, but this is OK. you can verify that everything is working correctly afterward by running:

$ VBoxControl --version
$ VBoxService --version

Setting up the vagrant User

Add the vagrant User

Next, we'll need to install a vagrant user so vagrant can login to the box. This enables several critical vagrant features like vagrant ssh and vagrant provision.

$ yum install -y sudo
$ useradd -m vagrant
$ usermod -aG wheel vagrant
$ echo vagrant | passwd vagrant --stdin
$ echo "vagrant ALL=(ALL) ALL" >> /etc/sudoers
$ echo "%wheel ALL=NOPASSWD: ALL" >> /etc/sudoers
$ echo 'Defaults env_keep="SSH_AUTH_SOCK"' >> /etc/sudoers

Finally, edit the /etc/sudoers file and add a bang ! to the requiretty line. This enables vagrant to sudo remotely.

Default !requiretty

Install opensshd

Since we want to be able to login to the box remotely we'll need to install opensshd:

$ yum install -y openssh-server
$ echo "UseDNS no" >> /etc/ssh/sshd_config

You can verify that it's running via:

$ service sshd status
$ /etc/init.d/sshd status

Add the vagrant public key

In order for the vagrant user to connect to the vm we'll need to add the vagrant public key to the vagrant user's authorized_keys file.

$ mkdir -m 0700 /home/vagrant/.ssh
$ curl -s https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub > \
> /home/vagrant/.ssh/authorized_keys
$ chown -R vagrant:vagrant /home/vagrant/.ssh
$ chmod -R 0600 /home/vagrant/.ssh/*

Install Chef

Wait...what's Chef? Vagrant uses something called a "provisioner" to deploy code and configuration to your box after you run vagrant up. Chef is one of these provisioners.

If you want to install the latest version of chef, it's pretty easy:

$ curl -L https://www.opscode.com/chef/install.sh | bash

If you want to install a specific version of chef, it's two lines:

$ curl -L https://www.opscode.com/chef/install.sh > /root/chef-install.sh
$ bash /root/chef-install.sh -v 10.18.2

This process installs chef using the chef omnibus, which includes a sandboxed version of ruby (so you don't need system ruby to cooperate, or even be installed). Afterwards, you can verify the installation via:

$ chef-client -v
Chef: 10.18.2

Opscode has a page that documents this process, which you can reference if you run into problems.

Reboot

When you're done making these changes, restart the machine.

$ shutdown -r now

Verify you can login with the vagrant user and sudo ls /root.

Packaging the Box

Once the OS is setup you'll need to package the box for shipment. This process differs depending on whether you're targeting VirtualBox or VMware.

First step in both cases, shut down your vm:

$ shutdown -h now

VMware

VMware puts its vms into ~/Documents/Virtual Machines.localized/, so I found mine via:

$ cd ~/Documents/Virtual Machines.localized/vagrant-centos62-x64.vmwarevm

In this directory you'll find a handful of files:

vagrant-cent62-x64.vmdk
vagrant-centos62-x64.nvram
vagrant-centos62-x64.plist
vagrant-centos62-x64.vmsd
vagrant-centos62-x64.vmx
vagrant-centos62-x64.vmxf

This is almost everything we need, but first we'll want to defrag (-d) and shrink (-k) the .vmdk file. Note that your .vmdk may be split into multiple files, but this doesn't matter.

$ vmware-vdiskmanager -d vagrant-cent62-x64.vmdk
$ vmware-vdiskmanager -k vagrant-cent62-x64.vmdk

Once the disk is smallified a bit, add a metadata.json file:

{
    "provider":"vmware_fusion"
}

And finally, tar it all up into a box.

$ tar -czvf vagrant-centos62-x64.vmware.box ./*

Aaand we're done! Skip to Adding and Upping the Box, below, to continue.

The vagrant docs have some notes on this process if you want to read more.

VirtualBox

Navigate into the directory where your box is located. On my system, this is:

$ cd ~/VirtualBox VMs/vagrant-cent62-x64.virtualbox

From here we'll need to do a few things. First, compact the disk:

$ VBoxManage modifyhd vagrant-cent62-x64.virtualbox.vdi --compact

This will squash the disk a bit so it will take up less space when we package it. Next, we'll need to export the VM into an odf package so vagrant can use it. I did this through the GUI.

Select your vm in the VirtualBox interface, click File menu, and then Export. In the dialog that appears, change the file extension to .odf. Click Continue and then Export.

When the process is complete you should have a handful of files that look like this:

vagrant-cent62-x64.virtualbox.ovf
vagrant-cent62-x64.virtualbox-disk1.vmdk
vagrant-cent62-x64.virtualbox.mf

For later steps, it will be easiest if these files are along in a directory so if they aren't, create a directory and move them. For example:

$ mkdir ~/Desktop/vbox
$ mv vagrant-cent62* ~/Desktop/vbox/

Now on to the configuration. First, we need to rename the ovf file to box.ovf so vagrant will recognize it.

$ mv vagrant-cent62-x64.virtualbox.ovf box.ovf

Next, we need to add a metadata.json file to our vbox folder to indicate the provider to use with this vm. This should go in the same folder as your vagrant-cent62* files from above.

```json metadata.json { "provider":"virtualbox" }

And finally, we need to indicate the base mac address of the vm. I also did this through the VirtualBox GUI. Right-click the VM, Settings, Network tab, click the arrow next to Advanced, and copy the mac address. Mine is `08002710BCC4`. We're going to put this in a `Vagrantfile` in the same vbox folder as above.

```ruby Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.base_mac = "08002710BCC4"
end

Now the folder should look like this:

Vagrantfile
metadata.json
vagrant-cent62-x64.virtualbox.ovf
vagrant-cent62-x64.virtualbox-disk1.vmdk
vagrant-cent62-x64.virtualbox.mf

We're ready to box! The special .box format vagrant uses is actually just a .tar with the above files and a .box extension, which we will make now, and then move to the desktop so we can find it easily.

$ tar -czvf vagrant-cent62-x64.virtualbox.box ./*
$ mv vagrant-cent62-x64.virtualbox.box ~/Desktop

Using the Box

You're ready to add the box and test!

$ vagrant box add vagrant-cent62-x64 \
> ~/Desktop/vagrant-cent62-x64.virtualbox.box --provider virtualbox

You can do the same for the other box (if you made one) using --provider vmware_fusion. The name of the box can be the same since --provider is used to differentiate them.

Note: if you have to repeat this process a few times (like I did when I was testing), you can remove the box from vagrant using vagrant box remove vagrant-cent62-x64 virtualbox. This will delete the copy that vagrant keeps in its cache, but will not touch the copy on your desktop. This is a good way to test downloading the box if you upload it somewhere.

Finally, we'll want to try using our box with vagrant up.

$ mkdir ~/Desktop/vagrant-test
$ cd ~/Desktop/vagrant-test
$ vagrant init

This will create a Vagrantfile in the current directory. Open it in your favorite editor and change config.vm.box to match the one we just added:

Vagrant.configure("2") do |config|
  config.vm.box = "vagrant-cent62-x64"
end

Then:

$ vagrant up --provider virtualbox

And you're off to the races!


Related

centos vagrant linux