Easy configuration management with Puppet

Holding the Strings

Update the Message of the Day

For the next project, I will begin with the following structure:


With the project structure created, I can move a simple file declaration into the init.pp file (Listing 1).

Listing 1

File Declaration

01 $ cat ./manifests/init.pp:
02 package { "update-motd":
03   ensure => installed
04 }
05 file { "/etc/update-motd.d/10-mymotd":
06     ensure => "present",
07     source  => "puppet:///modules/mypuppets/misc/10-mymotd",
08     owner   => 'root',
09     group   => 'root',
10     mode    => '0755',
11     require => Package['update-motd']
12 }

Next, I create ./files/misc/10-mymotd containing the following:

echo "Welcome to my puppet-managed server!"

In the preceding code, package asks Puppet to install the update-motd package; file asks it to ensure that the file is present and has the permissions as described, but also that this is done after the package update-motd is installed.

The contents of 10-mymotd are placed in a separate file and referenced using Puppet's syntax as:


With only this and a little googling, you should be able to rinse through dozens of services, packages, and configuration files, simply copying from your best configuration into Puppet.

MySQL is just a matter of the mysql package plus your my.cnf file. Setting up /etc/logrotate.d/our-logs with Puppet means you don't have to remember it.

Creating /etc/profile.d/binpath.sh will mean that a customization no one can quite remember (adding s3cmd to the PATH) doesn't have to be remembered. Most stuff on servers is just files, which is what makes Puppet so useful.

The line

require => Package['update-motd']

means that the corresponding file declaration won't be run until the package update-motd is installed.

Puppet doesn't run top-to-bottom but instead compiles a list of dependencies and runs the setup in dependency order.

This approach lets you chain together dependencies and make sure things are installed in the right order. It also means that running puppet apply twice is not the same as running puppet apply on a vanilla system twice, which can be painful for debugging.

I don't have room for the long explanation of this here, but the short answer is: You should use a virtualization tool such as EC2, Vagrant, or VMware to test your Puppet configuration on vanilla systems before you trust them.

Install and Configure Something Useful

So far, I've created a useless file and then created a mostly harmless file and installed a package. Now that I have a small Puppet project, I can install something useful by starting a new project with the following init.pp file (Listing 2).

Listing 2


01 package { "apache":
02     ensure => present,
03     name => $apache,
04     require  => Exec['apt-get update']
05 }
06 exec { 'apt-get update':
07 }
09 file { '/etc/apache2/sites-enabled/000-default':
10     ensure  => present,
11     source  => 'puppet:///modules/myproject/apache/000-default',
12     owner   => 'root',
13     group   => 'root',
14     mode    => '0664',
15     require => Package['apache'],
16     notify  => Service['apache']
17 }
19 file { '/var/www/index.html':
20     ensure  => present,
21     source  => 'puppet:///modules/myproject/web/index.html',
22     owner   => 'root',
23     group   => 'root',
24     mode    => '0664',
25     require => Package['apache'],
26     notify  => Service['apache']
27 }

Line 9 changes the default configuration of Apache and creates the 000-default file, which contains:

# Nothing here anymore.
# Ubuntu normally has a default on /var/www but we don't want it.

Line 19 creates a document root and puts an HTML page in it. This could be your app or just a holding page, but it gives you a starting point. You need to populate web/index.html with a little HTML – anything you like – then populate the file /etc/apache2/sites-enabled/mysite with:

<VirtualHost *:80>
  ServerName    exampledomain.localhost
  DocumentRoot /var/www/vhosts/

Now you have a web server config in your Puppet project, and running

puppet apply manifests/init.pp

lets Puppet do the hard work.

What Just Happened?

Once you get into the cycle of writing Puppet code, applying it, and testing it, you'll be more comfortable working with the Puppet system.

A Puppet module, like the one in Listing 2, describes resources: users, files, packages, and services. You go from a vanilla installation to a full configuration by layering resources on top of resources, which means they have to be set up in the right order. These are the dependencies, or meta parameters , as Puppet calls them: before, require, subscribe, and notify.

Puppet only makes changes when changes are needed. If the file exists and looks correct, Puppet won't make the change, but if it looks wrong, Puppet will update the file when you run puppet apply. Puppet configurations are distributed through modules. You'll find a heap of modules at Puppet Labs Forge [1]. With the latest versions of Puppet, you can install these modules so that you don't have to code complex implementations of MySQL by hand [2]. For example, Puppet Labs has master/slave configuration setups.

Buy ADMIN Magazine

Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

comments powered by Disqus