Creating a decentralized Puppet architecture
Puppet is a configuration management tool. You can use Puppet to configure and prevent configuration drift in a large number of client computers. If all your client computers are easily reached via a central location, you may choose to have a central Puppet server control all the client computers. In the centralized model, the Puppet server is known as the Puppet master. We will cover how to configure a central Puppet master in a few sections.
If your client computers are widely distributed or you cannot guarantee communication between the client computers and a central location, then a decentralized architecture may be a good fit for your deployment. In the next few sections, we will see how to configure a decentralized Puppet architecture.
As we have seen, we can run the puppet apply
command directly on a manifest file to have Puppet apply it. The problem with this arrangement is that we need to have the manifests transferred to the client computers.
We can use the Git repository we created in the previous section to transfer our manifests to each new node we create.
Getting ready
Create a new test node, call this new node whatever you wish, I'll use testnode
for mine. Install Puppet on the machine as we have previously done.
How to do it...
Create a bootstrap.pp
manifest that will perform the following configuration steps on our new node:
- Install Git:
package {'git': ensure => 'installed' }
- Install the
ssh
key to accessgit.example.com
in the Puppet user's home directory (/var/lib/puppet/.ssh/id_rsa
):File { owner => 'puppet', group => 'puppet', } file {'/var/lib/puppet/.ssh': ensure => 'directory', } file {'/var/lib/puppet/.ssh/id_rsa': content => " -----BEGIN RSA PRIVATE KEY----- … NIjTXmZUlOKefh4MBilqUU3KQG8GBHjzYl2TkFVGLNYGNA0U8VG8SUJq -----END RSA PRIVATE KEY----- ", mode => 0600, require => File['/var/lib/puppet/.ssh'] }
- Download the
ssh
host key fromgit.example.com
(/var/lib/puppet/.ssh/known_hosts
):exec {'download git.example.com host key': command => 'sudo -u puppet ssh-keyscan git.example.com >> /var/lib/puppet/.ssh/known_hosts', path => '/usr/bin:/usr/sbin:/bin:/sbin', unless => 'grep git.example.com /var/lib/puppet/.ssh/known_hosts', require => File['/var/lib/puppet/.ssh'], }
- Create a directory to contain the Git repository (
/etc/puppet/cookbook
):file {'/etc/puppet/cookbook': ensure => 'directory', }
- Clone the Puppet repository onto the new machine:
exec {'create cookbook': command => 'sudo -u puppet git clone git@git.example.com:repos/puppet.git /etc/puppet/cookbook', path => '/usr/bin:/usr/sbin:/bin:/sbin', require => [Package['git'],File['/var/lib/puppet/.ssh/id_rsa'],Exec['download git.example.com host key']], unless => 'test -f /etc/puppet/cookbook/.git/config', }
- Now when we run Puppet apply on the new machine, the
ssh
key will be installed for the Puppet user. The Puppet user will then clone the Git repository into/etc/puppet/cookbook
:root@testnode /tmp# puppet apply bootstrap.pp Notice: Compiled catalog for testnode.example.com in environment production in 0.40 seconds Notice: /Stage[main]/Main/File[/etc/puppet/cookbook]/ensure: created Notice: /Stage[main]/Main/File[/var/lib/puppet/.ssh]/ensure: created Notice: /Stage[main]/Main/Exec[download git.example.com host key]/returns: executed successfully Notice: /Stage[main]/Main/File[/var/lib/puppet/.ssh/id_rsa]/ensure: defined content as '{md5}da61ce6ccc79bc6937bd98c798bc9fd3' Notice: /Stage[main]/Main/Exec[create cookbook]/returns: executed successfully Notice: Finished catalog run in 0.82 seconds
Note
You may have to disable the
tty
requirement ofsudo
. Comment out the lineDefaults requiretty
at/etc/sudoers
if you have this line.Alternatively, you can set
user => Puppet
within the'create cookbook' exec
type. Beware that using the user attribute will cause any error messages from the command to be lost. - Now that your Puppet code is available on the new node, you can apply it using
puppet apply
, specifying that/etc/puppet/cookbook/modules
will contain the modules:root@testnode ~# puppet apply --modulepath=/etc/puppet/cookbook/modules /etc/puppet/cookbook/manifests/site.pp Notice: Compiled catalog for testnode.example.com in environment production in 0.12 seconds Notice: /Stage[main]/Base/File[/etc/motd]/content: content changed '{md5}86d28ff83a8d49d349ba56b5c64b79ee' to '{md5}4c4c3ab7591d940318279d78b9c51d4f' Notice: Finished catalog run in 0.11 seconds root@testnode /tmp# cat /etc/motd testnode.example.com Managed by puppet 3.6.2
How it works...
First, our bootstrap.pp
manifest ensures that Git is installed. The manifest then goes on to ensure that the ssh
key for the Git user on git.example.com
is installed into the Puppet user's home directory (/var/lib/puppet
by default). The manifest then ensures that the host key for git.example.com
is trusted by the Puppet user. With ssh
configured, the bootstrap ensures that /etc/puppet/cookbook
exists and is a directory.
We then use an exec
to have Git clone the repository into /etc/puppet/cookbook
. With all the code in place, we then call puppet apply
a final time to deploy the code from the repository. In a production setting, you would distribute the bootstrap.pp
manifest to all your nodes, possibly via an internal web server, using a method similar to curl http://puppet/bootstrap.pp >bootstrap.pp && puppet apply bootstrap.pp