Blame view

docs/puppet.md 5.49 KB
d4af4bf81   Will Farrington   Update our boxen ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
  # wtf is a puppet?
  
  Puppet is configuration management tool, written in Ruby, that compiles
  and runs code written in the Puppet language.
  
  But what does that actually mean in words a human can understand?
  Puppet is a tool that runs some code and that code can do all sorts of
  really powerful things to configure computers for you.
  
  Why do I want code mucking about with my laptop though?
  For the exact same reasons you want code configuring your server.
  In particular, homogeneity, reproducibility, reusability, and automation.
  When you use code to express how a machine should be configured,
  you know that all of your machines are configured the same way,
  that you can repeat that configuration any number of times,
  and that you don't have to do it manually each time.
  
  ## How does Puppet work?
  
  A Puppet run has two main steps: compilation and application.
  
  The compilations step starts with reading in what's called the site manifest.
  The site manifest is a single file that contains Puppet code that is responsible
  for telling the compiler what other Puppet code it should compile.
  
  Here are the first few lines of the default site manifest for Boxen:
  
  ```
  include boxen::environment
  include homebrew
  include gcc
  ```
  
  This tells the Puppet compiler that it must include the classes
  `boxen::environment`, `homebrew`, and `gcc`.
  Puppet will look for those classes on the modulepath.
  Typically, these files would be located at
  `$modulepath/boxen/manifests/environment.pp` and
  `$modulepath/homebrew/manifests/init.pp`.
  
  These might include other classes as well, or define **resources**.
  Resources are the building blocks of Puppet.
  A resource is an abstract description about a **thing** and the **state**
  that thing should be in.
  Every resource has a **type**, which is just a classification of resources.
  For example, we might have a resource `Package[mysql]` and its type would be
  `Package`.
  Puppet also supports multiple providers for types which act as pluggable
  backends depending on the operating system it's running on or the tools
  available on a particular system (in the case of the `Package` type,
  we might have providers for `yum` and for `aptget`).
  
  So now the Puppet compiler has finished tracking down and loading all the
  classes and resources it needs.
  Assuming we haven't encountered any compile-time errors, Puppet then begins
  the next phase of a run: applying the catalog.
  
  All of the resources Puppet has collected into the catalog have formed a
  DAG (directed, acyclic graph) that represents the order in which all these
  resources can be applied in a correct order.
  Puppet simply grabs the first "node" in this graph and traverses all nodes
  in the graph, applying each resource as it goes.
  
  Application of an individual resource starts with Puppet asking "is this
  resource in the state requested?" If the answer is yes, Puppet moves onto the
  next node and repeats this process. If the answer is no, Puppet will make
  whatever changes it can to reconcile the current state of the resource with
  what it should be, and then continues on.
  
  Once all resources have been applied, the Puppet run is complete.
  
  ## Declarative by nature
  
  One of the most confusing parts of the Puppet language to many newcomers is
  how the Puppet catalog orders and applies resources.
  The key thing to remember is that Puppet is a **declarative** language rather
  than a procedural one.
  In human words, the only order that matters in Puppet is order specified by
  relationships between resources.
  
  Here's an example of how someone new to Puppet might write a class:
  
  ``` puppet
  class mysql {
    file    { '/etc/my.cnf': source => 'puppet:///modules/mysql/my.cnf.erb' ; }
    package { 'mysql': }
    service { 'mysql': }
  }
  ```
  
  Someone expecting Puppet to be procedural would read this manifest as a list
  saying:
  
  * First create the my.cnf file
  * Then install the mysql package
  * Then start the mysql service
  
  The problem is, they would be **wrong**.
  There is no guarantee Puppet will apply these resources in that order,
  and it's quite likely that it won't.
  
  The proper way to ensure ordering in Puppet is to use one of the four
  **relationship metaparameters**:
  
  * before - Run this resource before another resource
  * notify - Same as before, but triggers a refresh on that resource
  * require - Run this resource after another resource
  * subscribe - Same as require, but triggers a refresh on that resource
  
  The behavior of these metaparameters should be pretty clear.
  Triggering a resource simply means that a resource will "refresh" itself.
  That typically means something like a `Service` resource restarting itself.
  It's important to remember that these metaparameters are valid on **any** resource.
  
  So, let's rewrite our example properly:
  
  ``` puppet
  class mysql {
    file { '/etc/my.cnf':
      source => 'puppet:///modules/mysql/my.cnf.erb',
      notify => Service['mysql']
    }
  
    package { 'mysql':
      notify => Service['mysql']
    }
  
    service { 'mysql': }
  }
  ```
  
  Now we're telling Puppet what order to apply these resources in:
  
  * Make sure /etc/my.cnf is in place before we start the mysql service
  * If /etc/my.cnf changes, tell mysql to restart
  * Make sure the mysql package is in place before we start the mysql service
  * If the mysql package changes, tell mysql to restart
  
  It's important to note that we didn't tell Puppet if `File[/etc/my.cnf]`
  should come before or after `Package[mysql]`.
  This is intentional.
  Most package managers won't overwrite a configuration file that already exists
  at package install-time, so in this case, we can assume installing the mysql
  package won't clobber our custom `/etc/my.cnf` file.