Puppet Tutorial for Linux: Powering up with Puppet
Puppet tutorial series
- Part 1: Powering up with Puppet 2.6
- Part 2: Client and Server
Puppet tutorial part 1: Powering up with Puppet 2.6
This Linux Puppet tutorial will help you install Puppet for the first time and start managing your servers.
Server configuration management (CM) is big news in the IT world these days. Rightly so, because Linux automation, devops and CM tools like Puppet and Chef can save you an enormous amount of time and money and help you build a really reliable and automated Linux infrastructure. In this tutorial, I’ll show you how to set up Puppet on Linux.
If you’re a sysadmin, or anyone else who manages a bunch of servers, CM tools can help you create patterns or recipes which you can use to build lots of identical servers, or cloud instances, or re-use in different places and for different applications. Automating Linux servers is a snap with Puppet. Puppet can manage thousands of servers as easily as just one or two - but let’s start with one or two!
If you’re a developer, Linux configuration management lets you write code which describes how servers should be set up - saving you the time and effort of doing it manually, and letting you create large, load-balanced groups of interchangeable servers which are guaranteed to be identically configured.
Installing Puppet
So much for the sales pitch. Let’s take a look at the steps required to get up and running with your first Puppet install (we’ll come to Chef in a later article).
Puppet example
For this Puppet example install, we’re going to assume you’re using an Ubuntu Linux machine. You can use a virtual machine for this, running in VMWare, VirtualBox or Xen if you like, or just a spare Linux box that happens to be lying around the office.
First, we need to install Puppet itself (you’ll need to log in as root or sudo su - on your server):
# apt-get install libopenssl-ruby rdoc libopenssl-ruby1.8 libreadline-ruby1.8 libruby1.8 rdoc1.8 ruby1.8 # wget http://puppetlabs.com/downloads/facter/facter-1.5.8.tar.gz # wget http://puppetlabs.com/downloads/puppet/puppet-2.6.4.tar.gz # tar xvzf facter-1.5.8.tar.gz # cd facter-1.5.8 # ruby install.rb # cd .. # tar xvzf puppet-2.6.4.tar.gz # cd puppet-2.6.4 # ruby install.rb # puppetd --version 2.6.4
There are gems and packages for Puppet, but for the sake of simplicity we’re installing from source; this also guarantees that you’ll get an up-to-date version, as Puppet is under active development and there are frequent new releases.
Creating a Puppet configuration
Next, we need to give Puppet something to do. The code snippets that tell Puppet how a machine should be configured are called manifests - like a shipping manifest, it tells Puppet what things (packages, users, files and other resources) should be present, and what they should contain.
The first thing to do is create a directory structure to hold your manifests. Puppet itself is not too fussy about how these are laid out, but we’re going to follow the Puppet community’s best practices document and use the recommended layout there. To save time, you can download a (nearly) empty template layout. To use this:
# cd /etc # wget http://bitfieldconsulting.com/files/powering-up-with-puppet.tar.gz # tar xvzf powering-up-with-puppet.tar.gz
You should now have an /etc/puppet directory with two subdirectories: modules and manifests. Roughly speaking, modules is where Puppet code lives, and manifests is where we specify which code should be applied to each machine under Puppet’s control.
Starting the Puppetmaster
Puppet comes in two parts: a server (the Puppetmaster) which listens for connections from clients and then tells them what manifest they should have, and a client program, which runs on each machine under Puppet control and connects to the Puppetmaster to get its manifest.
In our example, we’re running the master and client on the same machine, so let’s start the server:
# puppet master --mkusers
Running the Puppet client
With the Puppetmaster running, we can now check that everything is working as it should by running the client:
# puppet agent --test --server=`hostname` info: Caching catalog for localhost.localdomain info: Applying configuration version '1256130640' notice: Finished catalog run in 1.23 seconds
Creating Puppet classes
While technically we have just applied a Puppet manifest to the machine, it’s not a very interesting one, as it does nothing at all. Let’s create a manifest that manages a simple service: NTP (the Network Time Protocol). NTP is a daemon which keeps the machine’s clock synchronised with reference servers on the Internet.
First we’re going to create a class for the NTP service (if you haven’t done any object-oriented programming, a class is just a named chunk of code which we can refer to).
I’ve created a (nearly) empty template for you for the NTP class, so go ahead and edit the file /etc/puppet/modules/ntp/manifests/ntp.pp. Currently it looks like this:
class ntp {
}
Change it to this:
class ntp {
package { "ntp":
ensure => installed
}
service { "ntp":
ensure => running,
}
}
And save the file. We’ve now created a Puppet manifest which will manage the NTP daemon (ntp).
Creating Puppet nodes
Because Puppet can manage many machines at once, we still need to tell it to apply the NTP manifest to this machine. To do that, edit the file /etc/puppet/manifests/nodes.pp. You’ll see a template that looks like this:
node myserver {
}
Change it to this:
node myserver {
include ntp
}
(Replace myserver with the name of your machine - that is, the output of hostname -s.)
When Puppet runs, it looks for a node definition that matches the name of the client machine, and applies all the classes that it finds listed there with include.
You’ve now told Puppet that the server myserver (or whatever your machine is named) should have the NTP manifest applied to it.
Applying changes with Puppet
When you run Puppet again:
# puppet agent --test --server=`hostname` info: Caching catalog for localhost.localdomain info: Applying configuration version '1256130643' notice: //ntp/Service[ntp]/ensure: ensure changed 'stopped' to 'running' notice: Finished catalog run in 0.94 seconds
What happened here? Puppet looked up the manifest for myserver and found this:
package { "ntp":
ensure => installed
}
service { "ntp":
ensure => running,
}
This says that the package ntp should be installed, and the service ntp should be running. Your system may or may not have ntp already installed, but if not, Puppet will install it. Puppet checks to see if the service is started, and if it’s not, it starts the service for you. If you run Puppet again now:
# puppet agent --test --server=`hostname` info: Caching catalog for localhost.localdomain info: Applying configuration version '1256130643' notice: Finished catalog run in 0.66 seconds
you’ll see that Puppet does nothing, because the manifest is satisfied.
Puppet manifests are declarations
Puppet manifests are not a set of instructions, in the way that a shell script or a Ruby program is. They’re a declaration of how the world should be (or that part of it under Puppet’s control, anyway). If reality differs from the manifest, Puppet takes steps to adjust reality.
This means that Puppet isn’t just useful for building machines. It can also check them regularly to make sure that nothing important has changed, and if it has, to correct it. If you stop the NTP service manually and then run Puppet again, you’ll find Puppet restarts it.
Conversely, if you decide you no longer want NTP running on your machines, you can change the word running to stopped, and Puppet will enforce this policy on every machine that includes the NTP manifest (which could be hundreds or even thousands of servers).
Imagine making a change like that to a large production network by logging in to each machine in turn and running the necessary commands manually. Not only would it be tedious and time-consuming, but if you got interrupted halfway through, you might not remember which machines you’d fixed, and your whole network would be in an inconsistent and unknown state.
In our next thrilling episode
You’ve just powered up your system with Puppet! Next time in Puppet Tutorial part 2: Client and Server, we’ll look at how to set up Puppet to control multiple machines. If you’ve got any comments on this Puppet tuto, do let me know!
Puppet links
- Puppet Resources - our compendium of the best Puppet documentation and tutorials on the web
- Introduction to Puppet
- Puppet Wiki - the authoritative and accurate (or if not, at least definitively inaccurate) source for all things Puppet.
Puppet books
If you’re excited about Puppet and want to learn more, may I modestly recommend the Puppet 2.7 Cookbook? The Puppet 2.7 Cookbook takes you beyond the basics to explore the full power of Puppet, showing you in detail how to tackle a variety of real-world problems and applications. At every step it shows you exactly what commands you need to type, and includes full code samples for every recipe.


SCM and Sprinkle
Thanks for that short and sweet intro to puppet. What I find really mandatory is that you manage your modules and manifests with a source code control system. Otherwise you really might mess up your whole infrastructure with no way back :-(
Besides puppet and chef, we’re currently evaluating sprinkle (http://github.com/crafterm/sprinkle/,
http://redartisan.com/2008/5/27/sprinkle-intro). I’m not a big fan of a client-server solution, which applies changes “automagically” - we usually trigger rollouts ourselves. I understand that this can be done with puppet and chef, too, but it’s not the intended use.
Re: SCM and Sprinkle
Thanks! Sprinkle looks really interesting, I’ll check that out!
Your comment about using a source code control system is dead right - and this is essential for server configurations even if you’re not using a CM tool like Puppet, Chef or Sprinkle. . You’ve just given me a great idea for the next blog post! :D
Even with version control, it’s not trivial to roll back a system using Puppet - for example, if you add a user in Puppet and then remove it, Puppet won’t remove the user from the server. It might be useful to have a flag in Puppet that says ‘Everything on this box is managed by Puppet! If it’s not in the manifest, remove it!”
But that could cause other interesting problems…
removing things
That’s what
user { “foo”:
….
ensure => absent
}
is for.
You can leave that clause in place for
a few days and then clear up the recipe,
or alternatively just ‘userdel’ via ‘Command and Control’ layer
(ssh-in-a-for-loop, controltier, fabric, etc.).
Try to get Puppet from a repo if you can. We use EPEL for our Redhat boxes, other third party repos are available.
“If you’re building from source, you’re doin’ it wrong” :)
Looking forward to the next post :)
Thanks, and a suggestion
I appreciate you having put this together, thank you very much.
I suggest you update your puppet link to puppet-0.25.4 since there are some significant certificate issues with a first-time install of puppet-0.25.0.
ensure NTP installed
My CentOS 5.4 didn’t come with ntp.
yum install ntp
I tried to figure out how to ensure=>present, otherwise: yum install … but I couldn’t.
Re: ensure NTP installed
Right! Thanks for letting me know. I’ll update the tutorial to include this bit:
package { "ntp": ensure => installed }That should get it working for you.
Pupeteer?
I noticed that a lot of people come to this article through searching for “pupeteer linux”. Is everyone just misspelling “puppeteer linux”, or is there something called Pupeteer that I’m not aware of?
re:
Nice post. What kind of blog platform is this? I don’t think its wordpress. Where did you get your template? Is it prebuilt?
Jesse
Re: Blog platform
It’s powered by Drupal and managed entirely by Puppet! I’m a great believer in eating dogfood, in the computing sense that is. Not actually eating dogfood, because that would be rank.
Error message
Hi,
Thanks for the great tutorial. I followed it to the tee using puppet 2.6.2 and I’m getting the error
err: /Stage[main]/Ntp/Service[ntpd]/ensure: change from stopped to running failed: Could not find init script for ‘ntpd’
when I run $ sudo puppetd —test —server=myhostname
All of the files in your scaffolding are in /etc/puppet and I’ve made the changes you list. Has something changed in puppet 2.6.2 which would cause this?
Thanks,
Sam
Re: Error message
Hi Sam,
It sounds like on your platform, the “ntpd” service is called something different (maybe “ntp”). This is true on Debian/Ubuntu systems, for example.
Try changing the Service definition from
service { “ntpd”:
to
service { “ntp”:
and see if that works.
alias for name changes
is there a mechanism to alias ntpd to ntp to avoid this type of rework … I could see this being useful to transition migration
re:
Good thing I found this linux Puppet stuff as I wasn’t able to find this information elsewhere. I am bookmarking this for future use.
Tracie
re:
That’s great! I’m glad you found it useful. This Puppet tutorial is consistently one of the most popular pages on my site, so I must be doing something right!
I have personally taken the
I have personally taken the Puppet tutorial and as per my opinion everyone should take such type of coaching who are engaged with this platform.
VMware
How would you administer a large number of virtual machines with Puppet?
Thanks.
What I tend to do is build
What I tend to do is build the VM, install Puppet, run Puppet to bring in all of the standard configuration (user accounts, keys, sudoers, etc), and then freeze that image. When I spin up VMs, a further run of Puppet will bring in any changes since the image was frozen, but otherwise it’s a very fast start. I use this kind of setup to implement dynamic scaling on EC2, for example.
NPT isn't started, but server seems to respond
Hi,
Starting out, trying to get it working. I have a ubuntu laptop on which I’m running your tutorial:
err: /Stage[main]/Ntp/Service[ntp]/ensure: change from stopped to running failed: Could not find init script for ‘ntp’
Googling it gives this page: https://bugs.launchpad.net/ubuntu/+source/ntp/+bug/604717
Hmm, puppet seems broken. :)
Ubuntu 10.10 x86_a64
I don’t think it’s a Puppet
I don’t think it’s a Puppet problem - this is working for me on Ubuntu 10.04.
Can you run ‘service ntp start’? Or ‘/etc/init.d/ntp start’? That is most likely what Puppet will try to run.
Reply
Yup, I can run the second command there and it says ” * Starting NTP server ntpd —> [ OK ]”.
Hmm, that does sound like
Hmm, that does sound like Puppet is having trouble finding the correct way to start the service.
Try adding:
provider => "debian",to the definition of the NTP service. Sometimes Puppet doesn’t detect it correctly so this will force it to use the init scripts. Also, see if it works if you change the name of the service in Puppet to ‘ntpd’.
Awesome, puppet rulz!
Cool. The provider-part worked. Puppet may become a dog one day!
Question no. 2. I have .Net/mono web sites and application servers that I want to be able to build and configure with deployment from builds from git/teamcity’s artifacts, to provision to run on some number of virtual machines (vmware workstation or ec2 or windows azure). They can be run with nginx/mono_fastcgi. The end goal is to be able to go to a client, run a puppet script and get a complete CI/OSS development/git/web server/load balancer/app-server/amqp-rabbitmq/azure environment set up in a few minutes/hours — normally this takes a few days for me to set up. Are there any short cuts I can take to get to this nirivana for a creative developer?
How would you recommend getting started with this endeavour? Should I package everything into .deb-files? Keep a “file” object in puppet or how would I integrate them? And what about Windows - .msi-files or a transaction log with transactional NTFS that can be rolled back/compensated or WinRM or MsDeploy or simply Admin-rights for the puppet service and lots of small tools that it can use to check the computer state such that it can make it ‘right’?
There’s quite a few questions
There’s quite a few questions there :)
Email me at hello@bitfieldconsulting.com and I’ll try and answer them in more detail than I can here.
Your tutorial is very
Your tutorial is very detailed in manner. Thanks a lot for sharing this. My officemate have been wanting to learn more about this Puppet thingy but never got the chance to search extensively due to time constraints. I appreciate the links you included. It wraps up everything comprehensively.
Wonderful tutorial. You make
Wonderful tutorial. You make it so simple and easy to understand. Now i can solve someone’s doubt also. It has very good content. Keep helping.
Not working for 10.04
On a fresh 10.04 install the following problems exist -
1. There is no ‘ruby’ bin installed that can run ‘ruby install.rb’ as ruby 1.8 binarys is called ‘ruby1.8’
2. after running the puppet master command and trying to run puppet agent —test the following error is shown:
err: Could not retrieve catalog from remote server: Connection refused - connect(2)
I tried changing ownership of files in /etc/puppet (example template has undefined user id) and also tried explicitly referring to 127.0.0.1 as the server but always the same result.
Full error is: err: Could not
Full error is:
err: Could not retrieve catalog from remote server: Connection refused - connect(2)
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
Puppet
I have downloaded the puppet vm from puppetlabs.com. On running puppet agent —test —server=’learn.puppet.demo’ it also says Connection refused -connect(2) warning: Not using cache on failed catalog
err: could not retrieve catalog etc
puppet agent --test --server=`hostname` ERRORS OUT
I am trying evaluate ‘puppet’ and I am running inot an error.
When I run the command;
puppet agent —test —server=`hostname`
I get the following error;
err: Could not run Puppet configuration client: Could not retrieve local facts: uninitialized constant Facter::IPAddress
# puppet master
# puppet master —mkusers
Could not parse for environment production: Could not find file /root/master.pp
Oh well.
# puppet master
# puppet master —mkusers
Could not parse for environment production: Could not find file /etc/puppet/master.pp
Nor in here!
# puppet agent —test
# puppet agent —test —server=`hostname`
info: Retrieving plugin
err: /File[/var/lib/puppet/lib]: Failed to generate additional resources using ‘eval_generate’: Connection refused - connect(2)
err: /File[/var/lib/puppet/lib]: Could not evaluate: Connection refused - connect(2) Could not retrieve file metadata for puppet://srv5/plugins: Connection refused - connect(2)
err: Failed to prepare catalog: Could not run command from prerun_command: Execution of ‘/etc/puppet/etckeeper-commit-pre’ returned 1:
err: Could not run Puppet configuration client: Could not run command from postrun_command: Execution of ‘/etc/puppet/etckeeper-commit-post’ returned 1:
oops.
A step is missed out: #
A step is missed out:
# puppet master —mkusers
This did not start any deamons, so no puppet server is actaually running, which explains why the next command fails:
puppet agent —test —server=myIPaddress
# ps -eaf|grep puppet
root 17691 12508 0 11:32 pts/6 00:00:00 grep puppet
error
when i gave command puppetd —test in the terminal, I got this output:
info: Retrieving plugin
err: /File[/var/lib/puppet/lib]: Failed to generate additional resources using ‘eval_generate’: Connection refused - connect(2)
err: /File[/var/lib/puppet/lib]: Failed to retrieve current state of resource: Connection refused - connect(2) Could not retrieve file metadata for puppet://puppet/plugins: Connection refused - connect(2)
err: Could not retrieve catalog from remote server: Connection refused - connect(2)
warning: Not using cache on failed catalog
err: Could not retrieve catalog; skipping run
Re:
Try the same as root user (or with sudo) and this should work
re A step is missed out: #
As root run puppet master —mkusers —no-daemonize
And you should see where your errors are in your config files
take the quotes off the
take the quotes off the “ntpd” in /etc/puppet/modules/ntp/manifests/ntp.pp.
That will fix:
err: Could not retrieve catalog from remote server: Error 400 on SERVER: Could not match “ntpd”: at …
Post new comment