This document provides an overview of Puppet, an open source configuration management tool. It discusses key Puppet concepts like infrastructure as code, reproducible setups, and aligned environments. It also describes Puppet's architecture including the Puppet master, agent nodes, catalogs, resources, and the lifecycle of a Puppet run. The Puppet language is declarative and node-based. Resources are defined and organized into classes. Relationships between resources can be specified.
2. Configuration Management Advantage
• Infrastructure as Code
Track, Test, Deploy, Reproduce, Scale
• Reproducible setups
• Scale quickly
Done for one, use on many
• Aligned Environments
for development, testing, QA, production nodes
• Alternatives CM toolkit
Chef, CFEngine, SaltStack, Ansible
3. About Puppet
• The industry-leading configuration management
toolkit
• An open source IT Management tool written in Ruby
• Coding style is simular to Nagios
• Influenced by CFEngine
• Supports various OS
• Linux, Unix, OS X, Windows(>= 2.7)
4. Puppet Language
• DSL(Declarative Domain Specific Language)
• Defines STATES (Not procedure)
• Resources, Classes, and Nodes
Declaring resources(file, package, service, ...)
Groups of resources are organised in classes
A class may describe everything needed to configure an entire
service or application
Nodes that serve different roles will generally get different sets
of classes
5. How Puppet works
Every node checks in with a
puppet master
Do I look the way I'm supposed to look
I'm Puppet master
6. Lifecycle of a Puppet Run
1. Facts
The node sends data about its state to
the puppet master server.
2. Catalog
Puppet uses the facts to compile a
Catalog that specifies how the node
should be configured.
3. Report
Configuration changes are reported
back to the Puppet Master.
4. Report
Puppet's open API can also send data
to 3rd party tools.
7. Catalog
• Static documents which contain resources and
relationships
• Ruby object in memory
• Transmitted as JSON and persisted to disk as
YAML
• Agent nodes cache their most recent catalog
if the master fails compilation, re-use cached one.
8. Resource Abstraction Layer
types providers
ubuntu
SLES
macosx
Windows
user
file
package
service
exec
mount
group
host
RHEL
CentOS
9. Resource declaration
• file: The resource type
• ntp.conf: The title
• path: An attribute
• '/etc/ntp.conf': A value; in this case, a string
• template('ntp/ntp.conf'): A function call that returns a value; in this case, the
template function, with the name of a template in a module as its argument
file {'ntp.conf':
ensure => file,
path => '/etc/ntp.conf',
content => template('ntp/ntp.conf'),
owner => 'root',
mode => '0644',
}
10. Relationship meta-parameters
• before: Causes a resource to be applied before the target resource.
• require: Causes a resource to be applied after the target resource.
• notify: Causes a resource to be applied before the target resource. The target
resource will refresh if the notifying resource changes.
• subscribe: Causes a resource to be applied after the target resource. The
subscribing resource will refresh if the target resource changes.
package {'ntp':
ensure => installed,
before => File['ntp.conf'],
}
service {'ntpd':
ensure => running,
subscribe => File['ntp.conf'],
}
Package['ntp']
Service['ntpd']
monitor
11. Chaining Arrows
• -> (ordering arrow):
Causes the resource on the left to be applied before the resource on
the right. Written with a hyphen and a greater-than sign.
• ~> (notification arrow):
Causes the resource on the left to be applied first, and sends a refresh
event to the resource on the right if the left resource changes. Written
with a tilde and a greater-than sign.
Package['ntp'] -> File['ntp.conf'] ~> Service['ntpd']
File['ntp.conf'] Service['ntpd']Package['ntp']
Changed
Do restart
17. Resource References
• Resource References
# A reference to a file resource:
subscribe =>
# A type with a multi-segment name:
before =>
# A multi-resource reference:
require => File['/etc/apache2/httpd.conf',
'/etc/apache2/magic', '/etc/apache2/mime.types'],
# An equivalent multi-resource reference:
$my_files = ['/etc/apache2/httpd.conf', '/etc/apache2/magic',
'/etc/apache2/mime.types']
require => File[$my_files]
Concat::Fragment['apache_port_header'],
File['/etc/ntp.conf'],
22. Core Types - Service
service {
}
title :
ensure =>
enable =>
name =>
status =>
start =>
stop =>
restart =>
hasrestart =>
hasstatus =>
running | stopped ,
true | false ,
defaults to title
true | false,
true | false,
Manually specified commands for working
around bad init scripts
use stop+start instead of restart
use grepping process table instead of
status
eg) 'httpd':
23. Core Types - notify
notify {
}
title :
message => defaults to title
eg) 'This message is getting logged':
24. Core Types - exec
exec {
}
title :
command =>
path =>
refreshonly =>
onlyif =>
unless =>
The command to run; defaults to title
eg) ['bin', 'sbin', '/usr/bin', '/usr/sbin'],
true | false
only run, the result of this command is non-zero
eg) 'run-something':
only run as notified
only run, the result of this command is zero
25. Core Types - cron
cron {
}
title :
command =>
user =>
hour =>
minute =>
ensure =>
The command to run
eg) 'root',
eg) 2,
eg) 'logrotate':
eg) 2,
present | absent,
26. Core Types - user
user {
}
title :
uid =>
gid =>
shell =>
home =>
ensure =>
eg) '507',
eg) 'admin', or '10000',
eg) '/bin/bash',
eg) 'dave':
eg) '/home/dave',
present | absent,
managehome => true | false,
if it's false, you need to create user's home directory
manually.
27. Core Types - group
group {
}
title :
gid =>
ensure =>
eg) '10000',
eg) 'admin':
present | absent,
name => defaults to title
28. Variable
• prefixed with a $(dollar sign)
• any kind of data types can be assigned
$www_base_path = "/var/www"
file { "${www_base_path}/site":
ensure => directory,
}
$ssh_users = [ 'myself', 'someone' ]
class test {
$ssh_users += [ 'someone_else' ]
}
Interpolation
Appending Assignment
(Allow strings, arrays, hashes)
29. Facter/Facts
• Facter
• Puppet's cross-platform system profiling library
• Discovers and reports per-node facts which are
available in you Puppet manifests as variables
• Facts
Facts appears in Puppet as normal top-scope
variables
$ facter -p
32. Custom fact
• You can extend facter by writing ruby code
• http://docs.puppetlabs.com/facter/2.4/custom_facts.
html
Facter.add(:rubypath) do
setcode 'which ruby'
end
Facter.add(:rubypath) do
confine :osfamily => "Windows"
# Windows uses 'where' instead of 'which'
setcode 'where ruby'
end
40. 40
Templates
» Documents that combine code, data, and literal text
to produce a final rendered output.
» The goal of a template is to manage a complicated
piece of text with simple inputs.
41. 41
Template Syntax
<% Ruby codes %>
<%= Ruby expression %>
<%# comment %>
<% if @ssl -%>
## SSL directives
SSLEngine on
SSLCertificateFile <%= @ssl_cert %>
SSLCertificateKeyFile <%= @ssl_key %>
<% if @ssl_chain -%>
SSLCertificateChainFile <%= @ssl_chain %>
<% end -%>
No newline
45. Classes
• Named blocks of Puppet code, Stored in module
# A class with no parameters
class base::linux {
file { '/etc/passwd':
owner => 'root',
group => 'root',
mode => '0644',
}
file { '/etc/shadow':
owner => 'root',
group => 'root',
mode => '0440',
}
}
class
Type
Attribute
Type
Attribute
$variable
include other class
46. Defining class
• Class[‘apache’]
class apache {
package { ‘httpd’: ensure => latest }
service { ‘httpd’: ensure => running }
file { '/etc/httpd/conf': ensure => directory }
file { '/etc/httpd/conf/httpd.conf':
ensure => file,
require => [ Package['httpd'], File['/etc/httpd.conf'], ],
notify => Service['httpd'],
}
}
Looks OK, but Is it work on Debian?
47. Parameterized class
• Class[‘apache’]
class apache (
$package = ‘httpd’,
$service = ‘httpd’ ){
package { $package: ensure => latest }
service { $service : ensure => running }
…
}
# tests/debian.pp
class { ‘apache’
package => ‘apache2’,
service => ‘apache2’,
}
# tests/redhat.pp
class { ‘apache’ : }
# or
include apache
48. Params class
• Class[‘apache::params’]
class apache::params {
case $::osfamily {
'RedHat': {
$package = 'httpd'
$service = ‘httpd’
…
}
'Debian': {
$package = 'apache2'
$service = ‘apache2’
…
}
}
}
How to use it? The answer is inheritance
49. Class Inheritance
• Use inherits keyword
class test::parent {
$var = "parent"
notice("var in parent is ",$var)
}
class test::child inherits test::parent {
$var = "child"
notice("var in child is ",$var)
}
class test::nephew {
notice( "var in nephew is", $var)
}
[root@localhost modules]#
tree test/
test/
├── manifests
│ ├── child.pp
│ ├── init.pp
│ ├── nephew.pp
│ └── parent.pp
└── tests
└── inherits.pp
# manifests/init.pp
class test{
include test::child
include test::nephew
}
# tests/inherits.pp
include test[root@localhost test]# puppet apply tests/inherits.pp
Notice: Scope(Class[Test::Parent]): var in parent is parent
Notice: Scope(Class[Test::Child]): var in child is child
Notice: Scope(Class[Test::Nephew]): var in nephew is
Notice: Compiled catalog for localhost in environment production in 0.06
seconds
Notice: Finished catalog run in 0.01 seconds
50. Using params class
• Class[‘apache’]
class apache (
$package = $apache::params::package,
$service = $apache::params::service
) inherits apache::params {
package { $package: ensure => latest }
service { $service : ensure => running }
…
}
# tests/apache.pp
include apache
Use inheritance,
If you want to override some parent’s variables
or using params class
51. Declaring class
• include
standard way to declare classes
• require
become a dependency of the surrounding container
• contain (>= Puppet 3.4)
http://docs.puppetlabs.com/puppet/3.7/reference/lang_containm
ent.html#containing-classes
include-like behavior
-> multiple declaration is OK
class web {
}
include apache
include apache
include apache
include apache
class web {
}
class { ‘apache’: }
include apache
52. Declaring class
• class
Only way to declare parameterized classes
Resource-like behavior
-> Only one declaration is OK
# tests/debian.pp
class { ‘apache’
package => ‘apache2’,
service => ‘apache2’,
}
class web {
}
include apache
class { ‘apache’: }
include apache
54. Define
• Can be evaluated multiple times with different
parameters
• Once defined, acts like a new resource type
class apache::vhost ($docroot, $server_name, $server_admin) {
include apache # contains Package['httpd'] and Service['httpd']
include apache::params # contains common config settings
$vhost_dir = $apache::params::vhost_dir
file { "${vhost_dir}/${server_name}.conf":
content => template('apache/vhost-default.conf.erb'),
owner => 'www',
group => 'www',
mode => '0644',
require => Package['httpd'],
notify => Service['httpd'],
}
}
# tests/vhosts.pp
class { 'apache::vhost':
docroot => '/var/www/html',
server_name => 'www01.abc.com',
server_admin => 'sysadmin@abc.com',
}
class { 'apache::vhost':
docroot => '/var/www/html',
server_name => 'www02.abc.com',
server_admin => 'sysadmin@abc.com',
}
[root@localhost apache]# puppet apply tests/http.pp
Error: Duplicate declaration: Class[Apache::Vhost] is already declared in file
/etc/puppet/modules/apache/tests/http.pp:5; cannot redeclare at
/etc/puppet/modules/apache/tests/http.pp:11 on node localhost
Error: Duplicate declaration: Class[Apache::Vhost] is already declared in file
/etc/puppet/modules/apache/tests/http.pp:5; cannot redeclare at
/etc/puppet/modules/apache/tests/http.pp:11 on node localhost
55. Define
define apache::vhost2($docroot, $servername = $title, $server_admin) {
include apache # contains Package['httpd'] and Service['httpd']
include apache::params # contains common config settings
$vhost_dir = $apache::params::vhost_dir
file { "${vhost_dir}/${server_name}.conf":
content => template('apache/vhost-default.conf.erb'),
owner => 'www',
group => 'www',
mode => '0644',
require => Package['httpd'],
notify => Service['httpd'],
}
}
# tests/define.pp
apache::vhost2 { 'www01.abc.com':
docroot => '/var/www/html',
server_admin => 'sysadmin@abc.com',
}
apache::vhost2 { 'www02.abc.com':
docroot => '/var/www/html',
server_name => 'www02.abc.com',
server_admin => 'sysadmin@abc.com',
}
[root@localhost apache]# puppet apply tests/define.pp
Notice: Compiled catalog for localhost in environment production in 0.28 seconds
Notice:
/Stage[main]/Main/Apache::Vhost2[www02.abc.com]/File[/etc/httpd/conf.d/www02.ab
c.com.conf]/ensure: defined content as '{md5}39cab336c208f334fde6b07ef8c33445'
Notice: /Stage[main]/Apache/Service[httpd]: Triggered 'refresh' from 1 events
Notice: Finished catalog run in 0.78 seconds
56. functions
• Pre-defined chunks of Ruby code
• Runs during compilation time
• http://docs.puppetlabs.com/references/3.7.latest/function.html
• https://forge.puppetlabs.com/puppetlabs/stdlib
template eg) template('apache/vhost-default.conf.erb'),
str2bool eg) $_result = str2bool($::is_virtual)
fail eg) fail('$server_name is needed')
alert eg) alert('$server_name is empty, it’s filled with $title')
notice eg) notice( "var in parent is", $var)
57. Scope
# /etc/puppet/modules/scope_example/manifests/init.pp
class scope_example {
$variable = "Hi!"
notify {"Message from here: $variable":}
notify {"Node scope: $node_variable Top scope: $top_variable":}
}
# /etc/puppet/manifests/site.pp
$top_variable = "Available!"
node 'puppet.example.com' {
$node_variable = "Available!"
include scope_example
notify {"Message from node scope: $variable":}
}
notify {"Message from top scope: $variable":}
$ puppet apply site.pp
notice: Message from here: Hi!
notice: Node scope: Available! Top scope: Available!
notice: Message from node scope:
notice: Message from top scope:
58. 58
namespace
» Class and defined type names may be broken up
into segments
» Separated by double colon(::)
» analogous to the / [slash] in a file path.
class apache { ... }
class apache::mod { ... }
class apache::mod::passenger { ... }
define apache::vhost { ... }
apache <modulepath>/apache/manifests/init.pp
apache::mod <modulepath>/apache/manifests/mod.pp
apache::mod::passenger <modulepath>/apache/manifests/mod/passenger.pp
64. Roles & Profiles
• Implementation layer
(Profiles)
Includes regular classes
Might add resources directly
create_resources call
• Business layer (Roles)
Only includes profiles
No logic at all
One server - One role
65. Installation
• Debian OS family
[Client] sudo apt-get install puppet
[Server] sudo apt-get install puppetmaster
• RedHat OS family
Register EPEL or puppetlabs' repository
• # rpm -ivh http://yum.puppetlabs.com/el/6/
products/x86_64/puppetlabs-release-6-11.noarch.rpm
• [Client] yum install puppet
• [Server] yum install puppet-server
Red: Mac OSX only
Blue: Windows Only
Yellow: solaris
gray: solaris, FreeBSD, and some linux dist.
facter is an accessory project, it's written in ruby, facter on the command line is a ruby script
there are many resources that are mapped to facts. and we'll see later, we can make our own custom facts as well.
Red: Mac OSX only
Blue: Windows Only
Yellow: solaris
gray: solaris, FreeBSD, and some linux dist.