Virtualization for developers, Part 2

Welcome back! In Part 1 of this series we introduced you to Vagrant, a powerful tool for creating virtual environments of all flavors for development purposes. When we last left off we had configured Vagrant using the Vagrantfile and brought up our virtual environment based on an Ubuntu 12.04 image. In part two, we are going to now start automating the configuration of the virtual environment itself.

Introducing Puppet

Once a virtual environment has been created using Vagrant, in almost all cases there is going to be some configuration necessary of that environment itself before it can be useful. For example, if you are like me you’ll need to install some sort of LAMP stack so you can do some PHP development. To accomplish this we will need to add a provisioning technology to our Vagrant setup which will run in the virtual environment once it is created to install any packages, etc. necessary.

Out of the box Vagrant supports a number of different provisioning technologies such as Puppet, shell scripting, Chef, and more. In this article we will be using Puppet to configure and install our packages in the virtual environment. To get started, we need to head back into our Vagrantfile to add a new configuration block to specify our Puppet provisioner as shown below:

config.vm.provision :puppet do |puppet|
    puppet.options        = "--verbose --debug"
    puppet.manifests_path = "puppet/manifests"
    puppet.module_path    = "puppet/modules"
    puppet.manifest_file  = "site.pp"
    puppet.facter         = {
        "vagrant"     => true,
    }
end

There is a lot going on here in this configuration block, but if you are familiar with Puppet already most of these configuration settings should already be familiar to you. For those of you who aren’t certain what these mean, he’s a quick legend for you:

  • puppet.options are the command-line parameters to pass to puppet when it’s executed. In this case we basically tell it to output everything it’s doing by passing the --verbose and --debug arguments
  • puppet.manifests_path is the path (relative to the project root) where the puppet manifest files are stored and puppet.manifest_file is the specific puppet file to use to kick off the provisioning process
  • puppet.module_path is the path (relative to the project root) where the custom puppet modules associated with your project can be located.
  • puppet.facter is a set of key/value pairs to pass into puppet as facter values when the manifests run. These can then be used within puppet manifests to create conditional logic when provisioning the machine (i.e. doing something specific if the vagrant value is true

As you might guess based on these configuration values, our next step is to create some puppet manifests and modules for our project.

Puppet Modules

Puppet modules fall into two basic categories for our purposes and, depending on what you are doing, are brought into our virtual machine in two different ways. The first way, which is the most straightforward, is to create these modules in the puppet/modules directory of your project. While straightforward and great for home-grown modules, one of the cool things about puppet is that the Puppet Forge has a huge collection of pre-built puppet modules for you to use right off the shelf to do various tasks. We’ll look at both as we provision our virtual machine to serve up PHP pages.

Installing Forge Modules for Puppet

To install modules that exist in the puppet forge, you need to execute the puppet module install command in the virtual environment. Of course, you could SSH into the virtual environment and do this, but that sort of defeats the point when you are looking to automate the process of bringing up fully functional a virtual environment with no interaction. To overcome this, we’ll take a look at another type of provisioner available in Vagrant – the shell provisioner.

The shell provisioner, as its name implies, simply allows you to execute shell commands once the virtual machine has been brought online. This can be very useful for a number of things (as we’ll see when we talk about Amazon EC2 in the final part of our series), including doing things like installing perquisite puppet modules. In our case we are looking to install a few modules to help us manage the technologies we’re installing on our virtual machine (namely Apache, PHP, and Composer). To these ends we want to install the example42/apache, example42/php, and tPl0ch/composer modules. If we were doing this from within the virtual machine itself we could simply execute the following shell commands:

$ sudo mkdir -p /etc/puppet/modules
$ sudo puppet module install example42/apache
$ sudo puppet module install example42/php
$ sudo puppet module install tPl0ch/composer

To automate this step to be executed any time the virtual machine is provisioned by Vagrant, we can duplicate this behavior by adding the following configuration block to our Vagrantfile as shown:

config.vm.provision :shell do |shell|
    shell.inline = "mkdir -p /etc/puppet/modules;
    puppet module install example42/apache;
    puppet module install example42/php;
    puppet module install tPl0ch/composer"
end 

Now, when the virtual machine is provisioned it will automatically install the puppet modules we’ve specified as well. Coupled with our puppet provisioner we can now begin to use these modules transparently within our own puppet manifests (and modules) to build our local virtual environment automatically and exactly to the specifications we need it to be.

More to come later!

In the third and final segment to our three-part series, we will build our puppet manifests to install and configure a fully functional PHP and Apache environment ready for your development needs! Until then, if you are interested in reading up more on puppet, I strongly recommend you check out the Puppet Documentation and maybe browse around the Puppet Forge to get a feel of what’s available.

About John Coggeshall

John Coggeshall has been involved with the PHP project since 1996 and author of among other titles PHP 5 Unleashed. He now runs a PHP Consultancy and is Co-Founder of TestNotice providing technology solutions to the drug testing industry.