Learning Puppet basic thing
- 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.
- 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
- 13. Boolean, Undef
• Boolean
• true
all other strings, including “false"
all numbers, including 0 and negative numbers
array, hash event though it's empty
any resource references
false
undef
• Undef
nil in Ruby
- 14. Strings
• Strings
single-quoted strings
double-quoted strings
Escape sequences
Good: 'C:Program Files(x86)'
Bad: 'C:Program Files(x86)'
path => "${apache::root}/${apache::vhostdir}/${name}",
$ — literal dollar sign " — literal double quote
' — literal single quote — single backslash
n — newline r — carriage return
t — tab s — space
- 15. Numbers
• Numbers
$some_number = 8 * -7.992
$another_number = $some_number / 4
$product = 8 * +4 # syntax error
$product = 8 * 4 # OK
$product = 8 * .12 # syntax error
$product = 8 * 0.12 # OK
- 16. Arrays, Hashes
• Arrays
• Hashes
[ 'one', 'two', 'three' ] or [ 'one', 'two', 'three', ]
$foo = [ 'one', 'two', 'three' ]
notice( $foo[1] ) # one
notice( $foo[-2] ) # two
{ key1 => 'a', key2 => 'b' } or { key1 => 'a', key2 => 'b', }
$mysite = { port => 80,
server_name => { mirror0 => 'www.example.com',
mirror1 => 'abc.example.com' }
}
notice( $mysite[port] ) # 80
notice( $mysite[server_name][mirror1] ) # abc.example.com
- 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'],
- 20. Core Types - File
file {
}
title :
ensure =>
path =>
owner =>
group =>
mode =>
content =>
source =>
target =>
recurse =>
puppet:///modules/some_module/somefile,
template('some_module/somefile.erb'),
present | absent |file | directory | link ,
eg) '/etc/inetd.conf',
eg) 'root',
eg) 'root',
eg) '0644',
eg) '/etc/inet/inetd.conf',
true | false ,
'initd.conf':
- 21. Core Types - Package
package {
}
title :
ensure =>
source =>
present | latest | {version} | absent | purged,
eg) /tmp/abcpkg-1.1.rpm
eg) 'abcpkg':
- 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
- 31. Core Facts
architecture eg) x86_64
domain eg) example.com
fqdn eg) node01.example.com
filesystem eg) ext4, iso9660
hostname eg) node01
ipaddress eg) 10.0.2.15
kernelrelease eg) 2.6.32-504.8.1.el6.x86_64
memorysize eg) 458.39 MB
osfamily eg) RedHat
- 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
- 33. External Facts
• fact location
/etc/facter/facts.d
• Adding external facts
$ echo "application_tier=dev" > /etc/facter/facts.d/app.txt
$ facter application_tier
dev
$ cat <<EOF > /etc/facter/facts.d/mydata.yaml
yamlkey:
- hello
- world
EOF
$ facter yamlkey
["hello", "world"]
- 36. Conditional Statements
• Booleans • Arithmetic
$x = 1
$y = 2
($x == $y)
($x > $y)
($x < $y)
($x != $y)
($x < $y) and !($x < $y)
$x = 1
$y = 2
$x + $x == $y # true
$x - $x # 0
$y / 2 # 1
- 37. Conditional Statements
• if/elsif/else
• unless
if str2bool("$is_virtual") {
warning('Not work on virtual machine')
} elsif $::operatingsystem == 'Darwin' {
warning('Not support yet')
} else {
include ntp
}
unless $::memorysize > 1024 {
$maxclient = 500
}
- 38. Conditional Statements
• case
• selector
case $::hostname {
/^www/: { include apache }
/^dns/: { include bind }
/^mx[1-2]/: { include mx }
default: { include base }
}
$rootgroup = $::osfamily ? {
'Solaris' => 'wheel',
/(Darwin|FreeBSD)/ => 'wheel',
default => 'root',
}
- 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
- 42. 42
Templates - iteration
# ntp/init.pp
$nameservers = [ ‘ns1.example.com’,
‘ns2.example.com’,
‘ns3.example.com’ ]
$searchdomains = [ ‘inside.example.com’,
‘outside.example.com’,
‘under.example.com’]
file {“resolvconf”:
path => “/etc/resolv.conf”,
mode => ‘0644’,
owner => root,
group => root,
content => template('resolvconf.erb')
}
# /etc/puppet/manifests/resolv.conf.erb
# resolv.conf build by Puppet
domain <%= @domain %>
search <% @searchdomains.each do |domain| -%>
<%= domain -%><% end -%> <%= @domain %>
<% @nameservers.each do |server| -%>
nameserver <%= server %>
<% end -%>
/etc/resolv.conf
# resolv.conf build by Puppet
domain example.com
search inside.example.com outside.com under.example.com example.com
nameserver ns1.example.com
nameserver ns2.example.com
nameserver ns3.example.com
- 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
- 59. module
• Collection of manifests, resources, files, templates,
classes, and definitions.
• Can download pre-built modules from the Puppet
forge - http://forge.puppetlabs.com
$ puppet module generate daehyung-amodule
$ tree daehyung-amodule/
daehyung-amodule/
|-- Modulefile
|-- README
|-- manifests
| `-- init.pp
|-- spec
| `-- spec_helper.rb
`-- tests
`-- init.pp
foo/
|-- manifests
| |-- config.pp
| |-- defaults.pp
| |-- init.pp
| |-- install.pp
| `-- service.pp
|-- templates
| `-- foo-conf.erb
`-- tests
`-- init.pp
- 60. installing / uninstalling module
https://docs.puppetlabs.com/puppet/latest/referen
ce/modules_installing.html
puppet man module
puppet module list
puppet module search r10k
puppet module install zack/r10k --version 2.6.5
puppet module install zack-r10k-2.6.5.tar.gz --ignore-dependencies
puppet module upgrade zack/r10k --version 3.1.1
puppet module uninstall zack/r10k
- 61. 61
Keep this in mind
• Make a new module for you or company?
• Search from Puppet Forge first!
• The simple answer is NO!!!
- 62. Not mentioned in here
• ENC
• Hiera
• Environments
• r10k
• etc.
• too many, I’m still learning it ;)
- 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
Editor's Notes
- 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.
- - EPEL repository provides Puppet 2.7 only