O'Reilly logo

Managing Infrastructure with Puppet by James Loope

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

The Puppet Master

Running a central Puppet Master server will allow us to build configurations that are specific to a particular system and then hand them out to be executed on demand. It can be a central repository for the configuration of all servers in your data center, allowing for the centralized deployment of updates and applications.

Once the Puppet Master is installed, you’ll have an empty Puppet repository in /etc/puppet. When the Puppet Master starts up, the first file it loads is /etc/puppet/manifests/site.pp. Generally this file will include a nodes.pp file as well as set some default parameters. nodes.pp will tell the Puppet Master how to decide what classes it should apply to a system, called a node, when it checks in.


The Puppet Master and agent communicate over tcp port 8140. Make sure that any applicable firewall settings allow communication on that port between the two.

Let’s step through how to set up a node definition and apply a class to it with a central Puppet Master rather than by manually applying the manifest.

First, you’ll need to have both agent and master installed. For simplicity’s sake, these can be on the same system. Then set up a simple /etc/puppet/manifests/site.pp and nodes.pp.

This site.pp includes our nodes.pp and sets up a couple of defaults. The first of these is the filebucket. When Puppet makes some change to the filesystem, such as overwriting a config file with an update, it will make a backup of the original. When we define a filebucket on our Puppet Master server (which we assume to have the hostname puppet.example.com), we can then tell all the file type resource declarations to default their backup to that bucket. The way that I’ve set up that default here is called a metaparameter. When I declare a capitalized file resource with no title, the parameters I specify for it will become the default for that resource type. I’ve also specified a metaparameter default for the path of the exec resource type. Exec is used to execute arbitrary commands from the agent and it is convenient to have a standard default path set to look for executables:

# site.pp
import "nodes"

filebucket { main: server => "puppet.example.com" }

# defaults
File { backup => main }
Exec { path => "/usr/bin:/usr/sbin/:/bin:/sbin" }

In this example, I’ve defined a node explicitly as puppet.example.com and also as a default. The Puppet Master matches nodes based upon their hostnames and will fall back to a default node declaration if a matching node is not found. In this case, either way, the apps::ntp class will be applied to the node:

# nodes.pp

node default {
    include apps::ntp

node "puppet.example.com" {
    include apps::ntp

Now that we’ve told our Puppet Master how to identify our agent and what to do with it, we need to put the ntp manifest that we created earlier into the apps::ntp class. This way, when the agent runs it will execute our ntp installation just as it did when it was applied with the puppet apply command. We’ll put the class in /etc/puppet/modules/apps/init.pp.

You’ll notice that the source parameter has changed for our ntp.conf file. I’ve defined a string here that points to a place where our Puppet server expects module files to be kept. This puppet:///modules/apps/ntp/ntp.conf location maps to the /etc/puppet/modules/apps/files/ntp/ntp.conf location on our Puppet Master. This allows us to distribute files from the master to the clients without having to jump through any extra hoops, such as setting up nfs. Make sure to copy the ntp.conf file to the proper place on the master before continuing:

# apps/init.pp
class apps::ntp {
    package { 'ntp': ensure => '1:4.2.6.p2+dfsg-1ubuntu5' }

    file { '/etc/ntp.conf':
                    mode => '640',
                    owner => root,
                    group => root,
                    source => "puppet:///modules/apps/ntp/ntp.conf",
                    require => Package[ntp],

            service { "ntp":
                    ensure => running,
                    enable => true,
                    pattern => 'ntpd',
            subscribe => [Package["ntp"], File["/etc/ntp.conf"]],

With our node defined and importing the ntp class that we’ve written, we can now test out the agent. On the Puppet agent node, run sudo puppetd --test --noop --server puppet.example.com. This will tell the agent to run without daemonizing into the background (--test) and without actually modifying anything (--noop). The first run will not obtain a configuration from the Puppet Master because the agent has not yet been authenticated. It did, however, leave its certificate on the master for inspection. The next step in getting our agent and master talking is to have the Puppet Master sign our agent’s SSL certificate. This initial authentication step is done with the puppetca command. On the Puppet Master, run sudo puppetca -la. This will list all of the certificates in our Puppet Master’s certificate store. Certificates that are signed will have a + in front of them, and unsigned certificates will not. You should see a certificate for your agent that is not yet signed. To sign it, simply run sudo puppetca -sa. This will sign all the outstanding requests and allow those agents to talk to the master.


You can define client node names in the /etc/puppet/autosign.conf file in the format agenthost.example.com or even *.example.com. Names matching these patterns will be signed automatically by the master.

At this point, we should have a fully functional master and agent pair. The client certificate is signed, the node has a definition, and there is a class for the ntp installation assigned to it. Let’s prove that it works by running sudo puppetd --test --server puppet.example.com on our client. You should see the agent run through our manifest and install ntp.

Congratulations, you’ve taken a big step toward implementing a scalable configuration management architecture. Some deployments will need more complicated logic than packages and configuration files, but there are plenty of resource types, plug-ins, and examples to help you out. In the next chapter, we’ll look at the more advanced features of Puppet that will let you take these simple configuration definitions and apply them in a larger-scale fashion.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required