Creating Custom Vagrant VMs

Tobby Hagler, Director of Engineering
#Devops | Posted

For most Vagrant users, using pre-built VMs will do the trick. Practically every current version and flavor of Linux or Windows is available from places like www.vagrantbox.es. However, the occasional need arises when a pre-built box won't suffice.

There's a few reasons why that would be the case:

  • You need very a specific versions (distro and version of linux, experimental versions of PHP or Ruby, etc).

  • You need a bare-bones VM with nothing on it to test new servers (can't have Apache or Nginx because something else will be the web server).

  • To support an old legacy system, yeed an "old" environment that no one will have built a prepackaged box before.

  • You're debugging an install/uninstall process, and you need a pristine copy of a custom environment.

There are many guides to creating a Vagrant box already (I’ve listed some below), and lots of different techniques, so there's no need to try to create yet another HOWTO guide. However, There are some things that you'll want to do to make your life is easier and you are able to reuse a new VM quickly.

What you'll need:

  • An .iso file of your desired OS/distribution/version

  • Install VirtualBox or VMware Fusion (your preference)

  • Loads of free space on your local machine (watch out, SSD users)

In this blog post, I will be creating a VirtualBox VM with a fresh install of Centos 6.5. Feel free to substitute, deviate, or experiment as I walk through the various steps. The nice thing about VM boxes is that if you screw it up, you can just throw it away and start over.

Getting Started

The first few steps will involve creating a VirtualBox VM. You'll name it (like "centos-65-32"), set the OS and version. Spend some time going through the options and disable things you know you won't need, like USB ports and audio. You can lower the video memory if you plan to only use your final VM box via SSH rather than with VirtualBox.

Inside the VM, install only the essentials. Everything you install here will exist in the VMs that we instantiate later. You'll be logged in as root, so no need to use sudo for the following commands.

  1. y
  2.  
  3. um update -y && yum upgrade -y
  4.  
  5. yum install -y openssh-server vim nano wget gcc bzip2 zip unzip make linux-headers-generic build-essentials dkms
  6.  
  7. chkconfig sshd on
  8.  
  9. start sshd

Create a vagrant user. We won't use them now, but we will use this later once we're done; the 'vagrant ssh' automatically assumes the vagrant user. After creating the user, add the vagrant user public key, found at https://raw.github.com/mitchellh/vagrant/master/keys/vagrant.pub to the vagrant user's .ssh/authorized_keys file. While you're in there, you may want to add your public keys as well.

Guest Additions

Next, we'll need to install the Guest Additions. This is a commonly skipped step, but you're going to want these installed. These are the tools within the OS that let it know that it's a VM, and to behave within your host environment (such as your local development laptop). So even if you plan to keep your VM to a minimum state, you DO want to install Guest Additions.

While still as root, execute:

  1. wget http://download.virtualbox.org/virtualbox/4.3.8/VBoxGuestAdditions_4.3.8.iso
  2.  
  3. mkdir -p /media/VBoxGuestAdditions
  4.  
  5. mount -o loop,ro VBoxGuestAdditions_4.3.8.iso /media/VBoxGuestAdditions
  6.  
  7. sh /media/VBoxGuestAdditions/VBoxLinuxAdditions.run

If things seem to go wrong with installing the Guest Additions, you can check /var/log/vboxadd-install.log for details. Most of the time, the issue will be that you're missing some kernel source files or additional devel packages, and that log file will help you track down what's missing.

Network Settings

Within the VirtualBox GUI, edit the VM settings, and click on the Network tab. Adapter 1 will ALWAYS need to be set to NAT. Leave this alone, since the defaults should be fine for most use cases. Click the "Adapter 2" button, and choose "Host-only adapter" and set the name to "vboxnet0". There's no need to change this, but make note of the Mac Address settings -- VirtualBox will let you generate a new random Mac Address, which is good to know if you are running multiple VM instances simultaneously and you have mysterious problems with some of them not finding their network interfaces.

Delete this file: /etc/udev/rules.d/70-persistent-net.rules. Because our VM instances aren't running bare-metal hardware, these rules will occasionally cause your network interfaces to rename themselves. You'll see things like "udev: renamed network interface eth1 to eth2" in dmesg. This is because udev things that your network card is new every time you boot up the machine, and it renames it in an effort to be nice.

Disable iptables by using 'service iptables stop' and 'service ip6table stop' and make sure they stay stopped with 'chkconfig iptables off' and 'chkconfig ip6tables off'.

We also want to set up some zero-configuration networking, especially if you are hosting your VMs in OSX. Effectively, what this will do is announce your VMs presence on the local network to the host machine (your development laptop, for instance) so that you don’t have to constantly edit your local /etc/hosts file to point made-up local domains to your VM’s IP address.

Execute:

  1. wget http://www.mirrorservice.org/sites/dl.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
  2.  
  3. yum localinstall epel-release-6-8.noarch.rpm
  4.  
  5. yum -y install netatalk avahi  dbus nss-mdns
  6.  
  7. chkconfig netatalk on
  8.  
  9. chkconfig messagebus on
  10.  
  11. chkconfig avahi-daemon on
  12.  
  13. echo '- -transall -uamlist uams_randnum.so,uams_dhx.so,uams_dhx2.so -nosavepassword -advertise_ssh' >> /etc/netatalk/afpd.conf
  14.  
  15. service avahi-daemon start
  16.  
  17. service messagebus start
  18.  
  19. service netatalk start

 

Finally, edit the file /etc/avahi/avahi-daemon.conf and edit those first two lines for host-name and domain-name to something meaningful, like ‘generic’ and ‘local,’ which will later let you automatically visit your VM using http://generic.local.

Package the Box

Shut down your newly created VM using ‘shutdown -h now’ and you’re ready to package this up as a reusable VM box. Run the following commands:

  1. vagrant package --output centos-65-32.box --base centos-65-32
  2.  
  3. vagrant box add centos-65-32 centos-65-32.box
  4.  
  5. mkdir -p working/generic-vagrant && cd working/generic-vagrant
  6.  
  7. vagrant init centos-65-32

 

Vagrant packages up the VM you just created in VirtualBox and creates a box file for us, and then registers that box for use with Vagrant later. Vagrant init will create a ‘Vagrantfile’ which will be information about our specific Vagrant VM instance.

Final Configurations

Edit that Vagrantfile file. Make sure this line is uncommented, since this will be your “external” IP address. Vagrant will attempt to generate a unique IP address for you. You can change the IP to any unused, internally routable IP address you would like.

  1. config.vm.network "private_network", ip: "192.168.33.10"
  2.  
  3. Also uncomment “config.ssh.forward_agent = true”.
  4.  
  5. Then add these lines to the Vagrantfile for additional control of how the VMs are organized:
  6.  
  7. config.vm.provider :virtualbox do |vb|
  8.  
  9.  vb.customize ["modifyvm", :id, "--memory", "2048"]
  10.  
  11.  vb.customize ["modifyvm", :id, "--cpus", "2"]
  12.  
  13.  vb.customize ["modifyvm", :id, "--name", "Generic Dev Vagrant Box"]
  14.  
  15.  vb.customize ["modifyvm", :id, "--natdnspassdomain1", "off"]
  16.  
  17.  vb.customize ["modifyvm", :id, "--natdnspassdomain2", "off"]
  18.  
  19.  vb.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
  20.  
  21.  vb.customize ["modifyvm", :id, "--natdnsproxy1", "on"]
  22.  
  23. end

 

Finally, you can add the hostname (which you may want to change for every VM instance) by adding ‘config.vm.hostname = "generic"’. Generally, this hostname should match up with whatever you set in /etc/avahi/avahi-daemon.conf (you can edit this file once for each new VM you spin up).

Use Your New VM

Finally, run ‘vagrant up’ and this will instantiate and provision your new Vagrant VM. Once that is up and running, you can SSH into it using ‘vagrant ssh’.

You can copy Vagrantfile to another directory, and that will essentially be a new, separate VM instance. This is how you will be able to quickly create multiple VMs from that initial box we just created.

Because of our efforts with avahi-daemon and netatalk, you can now open OSX Finder to browse your local network. You’ll see the hostname of the VM listed. You’ll also be able to ping that hostname in Terminal. All of this happens without needing to add your VM’s IP address to your hosts file.

Additional Resources

Creating VirtualBox VMs (different methods to do the same thing)

Good Blog Posts About Vagrant

Tobby Hagler

Director of Engineering