Often during development it can be convenient or even necessary to spin up a virtual machine. And if you’re on a project with multiple developers you will likely want each to have their own instance. Doing that manually can require a lot of time. We want to automate this as much as possible so we’re not wasting time. Tools like VirtualBox, Vagrant and Puppet make this not only quick but repeatable and easy to share.
Prerequisites
You’ll need to have the following installed already:
- VirtualBox to run your VMs
- Vagrant to automatically configure VMs
- Ruby to run the Ruby-based tools you’ll be using
- Bundler for managing some Ruby dependencies
Note: I recommend you install VirtualBox 4.3.8 instead of the latest (4.3.10) as there is an issue with shared folders and the Guest Additions for 4.3.10
Setting up your project
First thing you’ll want to do is set up a directory for your new virtual machine. We’ll be creating an Ubuntu box for running Jenkins, the continuous integration server, so we’ll name it ubuntu-ci
:
$ mkdir ubuntu-ci
$ cd ubuntu-ci
Next, create a Gemfile
to manage your Ruby dependencies by doing the following:
$ bundle init
Then edit your Gemfile
and add the following dependencies:
gem 'puppet'
gem 'librarian-puppet'
Now use Bundler to install the dependencies:
$ bundle
We’ll be using librarian-puppet to manage our Puppet dependencies. The puppet gem makes Puppet commands available to Vagrant.
Create the Vagrant project file
Next you want to create a Vagrant project file that describes and configures your VM.
We’re going to use the hashicorp/precise32
box as our base, which is a simple 32-bit Ubuntu box that has Puppet installed. You can find other base boxes using Vagrant Cloud.
$ vagrant init hashicorp/precise32
This creates a Vagrantfile
in the current directory. For now we don’t care about its contents.
You can start up the VM with:
$ vagrant up
Once that’s done you should be able to ssh to the box:
$ vagrant ssh
Currently there isn’t much we can do with the box so let’s use Puppet to install something useful, like Jenkins, a continuous integration server.
Be sure to exit
out of your SSH session first!
Managing Puppet Dependencies
Puppet is great for automatically provisioning machines – installing services, creating users, populating files, etc. This can be done by creating modules and manifests files that describe the resources you want on a machine. It’s very powerful but can also be overwhelming if you’re in a hurry to get up and running.
Fortunately a lot of this work has already been done for you and can be found on the Puppet Forge. We’re going to leverage an existing module that sets up Jenkins for us. We’re also going to use librarian-puppet
to define and automatically install the module and its dependencies.
First, create a Puppetfile
to define which Puppet modules you’ll be using with the following command:
$ librarian-puppet init
Then edit the Puppetfile
to contain just the following:
#!/usr/bin/env ruby
forge "http://forge.puppetlabs.com"
mod 'rtyler/jenkins'
You can then install your Puppet dependencies by running:
$ librarian-puppet install
This will create a modules
directory and populate it with the Jenkins module and any of its dependencies.
Now to tell Vagrant to use Puppet.
Set up Vagrant to use Puppet
Start by editing your Vagrantfile
and adding the following inside the main Vagrant.configure
block:
config.vm.provision "puppet" do |puppet|
puppet.manifests_path = "manifests"
puppet.manifest_file = "site.pp"
puppet.module_path = ['modules']
end
config.vm.network "forwarded_port", guest: 8080, host: 8042
The first section tells Vagrant that we want to use Puppet to provision our machine, that the manifest file is in manifests/site.pp
and that modules are stored in the modules
directory.
The last line tells Vagrant to forward any requests locally on port 8042 to port 8080 on the VM so we can access Jenkins via with our browser.
Next, create the manifest directory for Puppet:
$ mkdir manifests
And create the manifest file itself:
$ touch manifests/site.pp
Now edit manifests/site.pp
to contain the following:
include ::apt
include jenkins
Tell Vagrant to reload so that your provisioning config is set up:
$ vagrant reload
And then finally provision the machine:
$ vagrant provision
You should now be able to access Jenkins via http://localhost:8042/.
You can continue to add and configure services by finding them on the Puppet Forge, adding them to your Puppetfile
, instantiating/configuring them in your manifests/site.pp
and then running vagrant provision
.
Sample code from the above can be seen here: https://github.com/spilth/spinning-useful-vms-quickly-vagrant-puppet-puppet-forge
.
About the Author