Circularspace

Puppet and vagrant

So I’ve been playing with Puppet and Chef for server provisioning. The two technologies attempt to fill the same, or at least similar tasks: managing system configuration. With Vagrant, testing these two systems has become extremely easy. Vagrant supports both methods for server provisioning and the turnaround time for the tests is extremely short.

I have tried for quite a while to run chef on a system, to no avail. I’ve often found that an unexpected crash puts end to my testing, whereas the first times I tried puppet I achieved success. I also feel the declarative style with which the puppet modules are built really suits the problems that puppet solves.

This post is less of a comparison of Chef vs Puppet, perhaps the first in a series comparing the two, but for now we start with Puppet.

Simple configuration

Tools used:

  • vagrant
  • puppet
  • librarian-puppet

I’m not going to go into details about the installation of the tools, apart from to say that vagrant is installed from the vagrant website and puppet/librarian-puppet are installed as gems.

A project can be completetly defined (for example for version control) in four files:

  • Vagrantfile
  • Puppetfile
  • Gemfile
  • manifests/default.pp (by convention)

The directory layout for the project, and what should be checked into version control is

.
├── Gemfile
├── Puppetfile
├── Vagrantfile
└── manifests
    └── default.pp

The Gemfile stores the ruby gem versions, the Puppetfile sets the puppet modules, the Vagrantfile configures the virtual machine and the manifests/default.pp file defines the state of the virtual machine.

Gemfile

A simple portable gemfile stores the required gems (puppet and librarian-puppet) and gives the option to version them. An example gemfile is

source "https://rubygems.org"

gem 'librarian-puppet'
gem 'puppet'

Vagrantfile

This is where the vagrant virtual machine configuration is stored. The operating system and provisioning settings are stored here. A minimal example is given below, and sets up the box to use (precise64) and configures the puppet provisioning.

VAGRANTFILE_API_VERSION = "2"

Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  config.vm.box = "precise64"

  config.vm.provision :puppet do |puppet|
    puppet.manifests_path = "manifests"
    puppet.manifest_file = "default.pp"
    puppet.module_path = "modules"
  end
end

librarian-puppet

A major part of development is the DRY principle, and applies to package configuration also. librarian-puppet allows pre-build and tested modules to install common packages. Puppetlabs maintain a repository of modules at puppet forge, or on github and these can be configured and managed through librarian-puppet. An example configuration is given below:

forge "https://forge.puppetlabs.com"

mod 'puppetlabs/stdlib'
mod 'puppetlabs/postgresql'
mod 'puppetlabs/apt'

where the mod lines define the required modules with the author prefix, and the forge line defines the source. The syntax is remarkably similar to the Gemfile.

manifests/default.pp

This file describes the final configuration. I recommend following the official puppet tutorial, an example file which installs vim can be:

exec { "apt-get update":
  path => "/usr/bin",
}

package { "vim":
  require => Exec["apt-get update"],
  ensure => present,
}

though this does not use the modules. These can be defined and configured by reopening the class declaration, e.g.

# Puppetfile
mod 'puppetlabs/postgresql'

# manifests/default.pp
exec { "apt-get update":
    path => "/usr/bin",
}

package { "vim":
    ensure => present,
    require => Exec["apt-get update"],
}

class { "postgresql::client":
    require => Exec["apt-get update"],
}

This configuration will install the vim and postgresql::client packages ensuring that apt-get update has been run before.

Starting a project from scratch

These files can be initialised through three commands:

  • bundle init,
  • vagrant init,
  • librarian-puppet init,

which are then configured to the users needs. Commands to run to create the full working system are

bundle install
bundle exec librarian-puppet install
vagrant up

Simple eh? More documentation for these files can be found: