~ubuntu-branches/ubuntu/raring/ansible/raring-backports

« back to all changes in this revision

Viewing changes to docsite/rst/playbooks_best_practices.rst

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2014-01-10 18:09:14 UTC
  • mfrom: (3.1.5 sid)
  • Revision ID: package-import@ubuntu.com-20140110180914-ywpe153kkue7ho86
Tags: 1.4.4+dfsg-1~ubuntu13.04.1
No-change backport to raring (LP: #1247541)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Best Practices
 
2
==============
 
3
 
 
4
Here are some tips for making the most of Ansible playbooks.
 
5
 
 
6
You can find some example playbooks illustrating these best practices in our `ansible-examples repository <https://github.com/ansible/ansible-examples>`_.  (NOTE: These may not use all of the features in the latest release, but are still an excellent reference!).
 
7
 
 
8
.. contents::
 
9
   :depth: 2
 
10
 
 
11
.. _content_organization:
 
12
 
 
13
Content Organization
 
14
++++++++++++++++++++++
 
15
 
 
16
The following section shows one of many possible ways to organize playbook content. Your usage of Ansible should fit your needs, however, not ours, so feel free to modify this approach and organize as you see fit.
 
17
 
 
18
(One thing you will definitely want to do though, is use the "roles" organization feature, which is documented as part
 
19
of the main playbooks page.  See :doc:`playbooks_roles`).
 
20
 
 
21
.. _directory_layout:
 
22
 
 
23
Directory Layout
 
24
````````````````
 
25
 
 
26
The top level of the directory would contain files and directories like so::
 
27
 
 
28
    production                # inventory file for production servers
 
29
    stage                     # inventory file for stage environment 
 
30
 
 
31
    group_vars/
 
32
       group1                 # here we assign variables to particular groups
 
33
       group2                 # ""
 
34
    host_vars/
 
35
       hostname1              # if systems need specific variables, put them here
 
36
       hostname2              # ""
 
37
 
 
38
    site.yml                  # master playbook
 
39
    webservers.yml            # playbook for webserver tier
 
40
    dbservers.yml             # playbook for dbserver tier
 
41
 
 
42
    roles/
 
43
        common/               # this hierarchy represents a "role"
 
44
            tasks/            #
 
45
                main.yml      #  <-- tasks file can include smaller files if warranted
 
46
            handlers/         # 
 
47
                main.yml      #  <-- handlers file
 
48
            templates/        #  <-- files for use with the template resource
 
49
                ntp.conf.j2   #  <------- templates end in .j2
 
50
            files/            #
 
51
                bar.txt       #  <-- files for use with the copy resource
 
52
                foo.sh        #  <-- script files for use with the script resource
 
53
            vars/             #
 
54
                main.yml      #  <-- variables associated with this role
 
55
 
 
56
        webtier/              # same kind of structure as "common" was above, done for the webtier role
 
57
        monitoring/           # ""
 
58
        fooapp/               # "" 
 
59
 
 
60
.. _stage_vs_prod:
 
61
 
 
62
How to Arrange Inventory, Stage vs Production
 
63
`````````````````````````````````````````````
 
64
 
 
65
In the example below, the *production* file contains the inventory of all of your production hosts.  Of course you can pull inventory from an external data source as well, but this is just a basic example.  
 
66
 
 
67
It is suggested that you define groups based on purpose of the host (roles) and also geography or datacenter location (if applicable)::
 
68
 
 
69
    # file: production
 
70
 
 
71
    [atlanta-webservers]
 
72
    www-atl-1.example.com
 
73
    www-atl-2.example.com
 
74
 
 
75
    [boston-webservers]
 
76
    www-bos-1.example.com
 
77
    www-bos-2.example.com
 
78
 
 
79
    [atlanta-dbservers]
 
80
    db-atl-1.example.com
 
81
    db-atl-2.example.com
 
82
 
 
83
    [boston-dbservers]
 
84
    db-bos-1.example.com
 
85
 
 
86
    # webservers in all geos
 
87
    [webservers:children]
 
88
    atlanta-webservers
 
89
    boston-webservers
 
90
 
 
91
    # dbservers in all geos
 
92
    [dbservers:children]
 
93
    atlanta-dbservers
 
94
    boston-dbservers
 
95
 
 
96
    # everything in the atlanta geo
 
97
    [atlanta:children]
 
98
    atlanta-webservers
 
99
    atlanta-dbservers
 
100
 
 
101
    # everything in the boston geo
 
102
    [boston:children]
 
103
    boston-webservers
 
104
    boston-dbservers
 
105
 
 
106
 
 
107
.. _groups_and_hosts:
 
108
 
 
109
Group And Host Variables
 
110
````````````````````````
 
111
 
 
112
Now, groups are nice for organization, but that's not all groups are good for.  You can also assign variables to them!  For instance, atlanta has its own NTP servers, so when setting up ntp.conf, we should use them.  Let's set those now::
 
113
 
 
114
    ---
 
115
    # file: group_vars/atlanta
 
116
    ntp: ntp-atlanta.example.com
 
117
    backup: backup-atlanta.example.com
 
118
 
 
119
Variables aren't just for geographic information either!  Maybe the webservers have some configuration that doesn't make sense for the database servers::
 
120
 
 
121
    ---
 
122
    # file: group_vars/webservers
 
123
    apacheMaxRequestsPerChild: 3000
 
124
    apacheMaxClients: 900
 
125
 
 
126
If we had any default values, or values that were universally true, we would put them in a file called group_vars/all::
 
127
 
 
128
    ---
 
129
    # file: group_vars/all
 
130
    ntp: ntp-boston.example.com
 
131
    backup: backup-boston.example.com 
 
132
 
 
133
We can define specific hardware variance in systems in a host_vars file, but avoid doing this unless you need to::
 
134
 
 
135
    ---
 
136
    # file: host_vars/db-bos-1.example.com
 
137
    foo_agent_port: 86
 
138
    bar_agent_port: 99
 
139
 
 
140
.. _split_by_role:
 
141
 
 
142
Top Level Playbooks Are Separated By Role
 
143
`````````````````````````````````````````
 
144
 
 
145
In site.yml, we include a playbook that defines our entire infrastructure.  Note this is SUPER short, because it's just including
 
146
some other playbooks.  Remember, playbooks are nothing more than lists of plays::
 
147
 
 
148
    ---
 
149
    # file: site.yml
 
150
    - include: webservers.yml
 
151
    - include: dbservers.yml
 
152
 
 
153
In a file like webservers.yml (also at the top level), we simply map the configuration of the webservers group to the roles performed by the webservers group.  Also notice this is incredibly short.  For example::
 
154
 
 
155
    ---
 
156
    # file: webservers.yml
 
157
    - hosts: webservers
 
158
      roles:
 
159
        - common
 
160
        - webtier
 
161
 
 
162
.. _role_organization:
 
163
 
 
164
Task And Handler Organization For A Role
 
165
````````````````````````````````````````
 
166
 
 
167
Below is an example tasks file that explains how a role works.  Our common role here just sets up NTP, but it could do more if we wanted::
 
168
 
 
169
    ---
 
170
    # file: roles/common/tasks/main.yml
 
171
 
 
172
    - name: be sure ntp is installed
 
173
      yum: pkg=ntp state=installed
 
174
      tags: ntp
 
175
 
 
176
    - name: be sure ntp is configured
 
177
      template: src=ntp.conf.j2 dest=/etc/ntp.conf
 
178
      notify:
 
179
        - restart ntpd
 
180
      tags: ntp
 
181
 
 
182
    - name: be sure ntpd is running and enabled
 
183
      service: name=ntpd state=running enabled=yes
 
184
      tags: ntp
 
185
 
 
186
Here is an example handlers file.  As a review, handlers are only fired when certain tasks report changes, and are run at the end
 
187
of each play::
 
188
 
 
189
    ---
 
190
    # file: roles/common/handlers/main.yml
 
191
    - name: restart ntpd
 
192
      service: name=ntpd state=restarted
 
193
 
 
194
See :doc:`playbooks_roles` for more information.
 
195
 
 
196
 
 
197
.. _organization_examples:
 
198
 
 
199
What This Organization Enables (Examples)
 
200
`````````````````````````````````````````
 
201
 
 
202
Above we've shared our basic organizational structure.
 
203
 
 
204
Now what sort of use cases does this layout enable?  Lots!  If I want to reconfigure my whole infrastructure, it's just::
 
205
 
 
206
    ansible-playbook -i production site.yml
 
207
 
 
208
What about just reconfiguring NTP on everything?  Easy.::
 
209
 
 
210
    ansible-playbook -i production site.yml --tags ntp
 
211
 
 
212
What about just reconfiguring my webservers?::
 
213
 
 
214
    ansible-playbook -i production webservers.yml
 
215
 
 
216
What about just my webservers in Boston?::
 
217
 
 
218
    ansible-playbook -i production webservers.yml --limit boston
 
219
 
 
220
What about just the first 10, and then the next 10?::
 
221
   
 
222
    ansible-playbook -i production webservers.yml --limit boston[0-10]
 
223
    ansible-playbook -i production webservers.yml --limit boston[10-20]
 
224
 
 
225
And of course just basic ad-hoc stuff is also possible.::
 
226
 
 
227
    ansible -i production -m ping
 
228
    ansible -i production -m command -a '/sbin/reboot' --limit boston 
 
229
 
 
230
And there are some useful commands to know (at least in 1.1 and higher)::
 
231
 
 
232
    # confirm what task names would be run if I ran this command and said "just ntp tasks"
 
233
    ansible-playbook -i production webservers.yml --tags ntp --list-tasks
 
234
 
 
235
    # confirm what hostnames might be communicated with if I said "limit to boston"
 
236
    ansible-playbook -i production webservers.yml --limit boston --list-hosts
 
237
 
 
238
.. _dep_vs_config:
 
239
 
 
240
Deployment vs Configuration Organization
 
241
````````````````````````````````````````
 
242
 
 
243
The above setup models a typical configuration topology.  When doing multi-tier deployments, there are going
 
244
to be some additional playbooks that hop between tiers to roll out an application.  In this case, 'site.yml'
 
245
may be augmented by playbooks like 'deploy_exampledotcom.yml' but the general concepts can still apply.
 
246
 
 
247
Consider "playbooks" as a sports metaphor -- you don't have to just have one set of plays to use against your infrastructure
 
248
all the time -- you can have situational plays that you use at different times and for different purposes.
 
249
 
 
250
Ansible allows you to deploy and configure using the same tool, so you would likely reuse groups and just
 
251
keep the OS configuration in separate playbooks from the app deployment.
 
252
 
 
253
.. _stage_vs_production:
 
254
 
 
255
Stage vs Production
 
256
+++++++++++++++++++
 
257
 
 
258
As also mentioned above, a good way to keep your stage (or testing) and production environments separate is to use a separate inventory file for stage and production.   This way you pick with -i what you are targeting.  Keeping them all in one file can lead to surprises!
 
259
 
 
260
Testing things in a stage environment before trying in production is always a great idea.  Your environments need not be the same
 
261
size and you can use group variables to control the differences between those environments.
 
262
 
 
263
.. _rolling_update:
 
264
 
 
265
Rolling Updates
 
266
+++++++++++++++
 
267
 
 
268
Understand the 'serial' keyword.  If updating a webserver farm you really want to use it to control how many machines you are
 
269
updating at once in the batch.
 
270
 
 
271
See :doc:`playbooks_delegation`.
 
272
 
 
273
.. _mention_the_state:
 
274
 
 
275
Always Mention The State
 
276
++++++++++++++++++++++++
 
277
 
 
278
The 'state' parameter is optional to a lot of modules.  Whether 'state=present' or 'state=absent', it's always best to leave that
 
279
parameter in your playbooks to make it clear, especially as some modules support additional states.
 
280
 
 
281
.. _group_by_roles:
 
282
 
 
283
Group By Roles
 
284
++++++++++++++
 
285
 
 
286
A system can be in multiple groups.  See :doc:`intro_inventory` and :doc:`intro_patterns`.   Having groups named after things like
 
287
*webservers* and *dbservers* is repeated in the examples because it's a very powerful concept.
 
288
 
 
289
This allows playbooks to target machines based on role, as well as to assign role specific variables
 
290
using the group variable system.
 
291
 
 
292
See :doc:`playbooks_roles`.
 
293
 
 
294
.. _os_variance:
 
295
 
 
296
Operating System and Distribution Variance
 
297
++++++++++++++++++++++++++++++++++++++++++
 
298
 
 
299
When dealing with a parameter that is different between two different operating systems, the best way to handle this is
 
300
by using the group_by module.
 
301
 
 
302
This makes a dynamic group of hosts matching certain criteria, even if that group is not defined in the inventory file::
 
303
 
 
304
   ---
 
305
 
 
306
   # talk to all hosts just so we can learn about them 
 
307
 
 
308
   - hosts: all
 
309
     tasks:
 
310
        - group_by: key={{ ansible_distribution }}
 
311
 
 
312
   # now just on the CentOS hosts...
 
313
 
 
314
   - hosts: CentOS
 
315
     gather_facts: False
 
316
     tasks:
 
317
        - # tasks that only happen on CentOS go here
 
318
 
 
319
If group-specific settings are needed, this can also be done. For example::
 
320
 
 
321
    ---
 
322
    # file: group_vars/all
 
323
    asdf: 10
 
324
 
 
325
    ---
 
326
    # file: group_vars/CentOS
 
327
    asdf: 42
 
328
 
 
329
In the above example, CentOS machines get the value of '42' for asdf, but other machines get '10'.
 
330
 
 
331
.. _ship_modules_with_playbooks:
 
332
 
 
333
Bundling Ansible Modules With Playbooks
 
334
+++++++++++++++++++++++++++++++++++++++
 
335
 
 
336
.. versionadded:: 0.5
 
337
 
 
338
If a playbook has a "./library" directory relative to its YAML file, this directory can be used to add ansible modules that will
 
339
automatically be in the ansible module path.  This is a great way to keep modules that go with a playbook together.
 
340
 
 
341
.. _whitespace:
 
342
 
 
343
Whitespace and Comments
 
344
+++++++++++++++++++++++
 
345
 
 
346
Generous use of whitespace to break things up, and use of comments (which start with '#'), is encouraged.
 
347
 
 
348
.. _name_tasks:
 
349
 
 
350
Always Name Tasks
 
351
+++++++++++++++++
 
352
 
 
353
It is possible to leave off the 'name' for a given task, though it is recommended to provide a description 
 
354
about why something is being done instead.  This name is shown when the playbook is run.
 
355
 
 
356
.. _keep_it_simple:
 
357
 
 
358
Keep It Simple
 
359
++++++++++++++
 
360
 
 
361
When you can do something simply, do something simply.  Do not reach
 
362
to use every feature of Ansible together, all at once.  Use what works
 
363
for you.  For example, you will probably not need 'vars',
 
364
'vars_files', 'vars_prompt' and '--extra-vars' all at once,
 
365
while also using an external inventory file.
 
366
 
 
367
.. _version_control:
 
368
 
 
369
Version Control
 
370
+++++++++++++++
 
371
 
 
372
Use version control.  Keep your playbooks and inventory file in git
 
373
(or another version control system), and commit when you make changes
 
374
to them.  This way you have an audit trail describing when and why you
 
375
changed the rules that are automating your infrastructure.
 
376
 
 
377
.. seealso::
 
378
 
 
379
   :doc:`YAMLSyntax`
 
380
       Learn about YAML syntax
 
381
   :doc:`playbooks`
 
382
       Review the basic playbook features
 
383
   :doc:`modules`
 
384
       Learn about available modules
 
385
   :doc:`developing_modules`
 
386
       Learn how to extend Ansible by writing your own modules
 
387
   :doc:`intro_patterns`
 
388
       Learn about how to select hosts
 
389
   `Github examples directory <https://github.com/ansible/ansible/tree/devel/examples/playbooks>`_
 
390
       Complete playbook files from the github project source
 
391
   `Mailing List <http://groups.google.com/group/ansible-project>`_
 
392
       Questions? Help? Ideas?  Stop by the list on Google Groups