I've had a lot of requests for a better understanding of how to
organize playbook content, so I've written a lot more about how I do
it. Obviously everyone is going to have their own approach, so our
best practice here is mostly a suggestion, but it's not far off from
what a lot of people do. But in the end, it's just one way to do it.
Some review on this would be welcome before we push it to the doc
site:
* playbooks are mappings between groups and roles
* a particular style of organization allows more power in selectively
running things if so organized, I like to have playbooks for each
"class" of system and think of playbooks as mapping groups to roles.
* files/templates/handlers/tasks as subdirectories allows for
organization of content a little bit. Subdirectories based on role.
* where to put variable defaults (a very common request) and to show
an example of group_vars/host_vars
* how to keep staging and production seperate and to prevent surprises
I'm going to be doing an example repo of what this looks like on
github here, but I also wanted to be able to explain it on the docs
page as well.
I freehanded all of the YAML without checking it (don't try this at
home!), so there may be some errors -- patches to the RST files are
fair game!
One question regarding tags: I couldn’t find anything in the documentation regarding the “tags=…” argument on includes. What is the semantics of that? Does it limit the included tasks to those with the given tag (which would make the example seem a bit odd) or does it add the given tag to the included tasks?
Michael,
in looking at the layout you describe - I worry how well that layout scales for middle-largish deployments.
In places with 200ish hosts - if you have 50 different variations of server that top level directory is going to be difficult to traverse and find everything in.
Maybe a playbooks subdir?
Additionally, in the fedora ansible repo I setup I had added subdirs of 'groups' and 'hosts' for playbooks so I could tell when a specific system had its own, specific playbook vs being a member of a group.
Would either of those items make sense for adding to the best practices?
I tend to organize my playbooks as:
/etc/ansible/playbooks/desktops/archlinux/playbook_here.yml
/etc/ansible/playbooks/servers/debian/playbook_here.yml
etc…
I don't use tags as part of my normal workflow yet, but I use them a lot to debug specific tasks. Rather create another playbook with just that task, or run the entire playbook, I add a tag to the task(s) I am trying to debug:
Michael,
in looking at the layout you describe - I worry how well that layout scales
for middle-largish deployments.
In places with 200ish hosts - if you have 50 different variations of server
that top level directory is going to be difficult to traverse and find
everything in.
Yeah, probably. I think about places with 200 hosts all the time (we
have quite a few people running much much larger), but they are
generally *mostly* homogenous.
Maybe a playbooks subdir?
Additionally, in the fedora ansible repo I setup I had added subdirs of
'groups' and 'hosts' for playbooks so I could tell when a specific system
had its own, specific playbook vs being a member of a group.
Not sure I would see host specifics playbooks being recommended, per
se, but it's a possible thing people could do if they wanted.
If a host is the only one in the role, I'd still like to see it
modelled based on the group.
I agree. I have a directory structure very similar to the Michael's best practice but with a few differences:
-I don't have any playbook at the top level. It does have the disadvantage that all references have to point to ../.
-I find webtier, monitoring too simplistic. Typically an "apps" is a combination of a web server, a database server etc.... Yet, install tomcat or nginx is always the same thing, it's their customisations that makes a big difference, so I have a basic install playbook, then each apps has its own customisation of which makes an include of the basic install. So I have something along these lines:
In this example:
logisctics-all.playbook.yaml makes an include of logistics-nginx.playbook.yaml and logistics-nginx.tasks.yaml
logistics-nginx.playbook.yaml makes an include of logistics-nginx.tasks.yaml and ../install-software/install-nginx.playbook.yaml
etc...
-depending on the size of a project or apps, I'll create subriectories for tasks, vars, etc... specific to that apps, or I'll just keep them all in one dir (if there are only a handful of files). Because I mix files into the same directory, I do add .paylbook., .tasks., .vars., to all my files.
Using multiple inventory files is an interesting idea -- making the concept of, say, 'hosts: all' dynamic. Much simpler than managing corresponding top level groups or multiple target specific playbooks.
Is there sample best practice on how to write playbooks for multiple OS, like for Centos5/6 and Ubuntu, Like deciding to use yum or apt etc.as of now, i am using global_var.yml and deciding if its ubuntu or centos and which flavor and run certain actions based on that.
Also Would be nice for Best Practice’s to be for large deployments or have separate for small(easy) and large(more complex). So people learning to use Ansible know how to setup so it can scale easily. I personally would be very interested in a complex playbook best practices , with documentation on what each playbook does and how it works. (Every one learns differently i learn by examples), Let me know if this is reasonable.
Is there sample best practice on how to write playbooks for multiple OS,
like for Centos5/6 and Ubuntu, Like deciding to use yum or apt etc.as of
now, i am using global_var.yml and deciding if its ubuntu or centos and
which flavor and run certain actions based on that.
There is the $ansible_pkg_mgr fact but because so many other details
are different I really think (in any tool)
seperating those is appropriate in many cases.
Also Would be nice for Best Practice's to be for large deployments or have
separate for small(easy) and large(more complex). So people learning to use
Ansible know how to setup so it can scale easily. I personally would be very
interested in a complex playbook best practices , with documentation on what
each playbook does and how it works. (Every one learns differently i
learn by examples), Let me know if this is reasonable.
I think what I decided to show was 80% complex-ish, and at that point,
individual needs may make things vary quickly.
Though I would like more people to show github examples of what they
are doing and maybe we can link to several in that section to show
other approaches?
Is there sample best practice on how to write playbooks for multiple OS,
like for Centos5/6 and Ubuntu, Like deciding to use yum or apt etc.as of
now, i am using global_var.yml and deciding if its ubuntu or centos and
which flavor and run certain actions based on that.
There is the $ansible_pkg_mgr fact but because so many other details
are different I really think (in any tool)
seperating those is appropriate in many cases.
Also Would be nice for Best Practice’s to be for large deployments or have
separate for small(easy) and large(more complex). So people learning to use
Ansible know how to setup so it can scale easily. I personally would be very
interested in a complex playbook best practices , with documentation on what
each playbook does and how it works. (Every one learns differently i
learn by examples), Let me know if this is reasonable.
I think what I decided to show was 80% complex-ish, and at that point,
individual needs may make things vary quickly.
Though I would like more people to show github examples of what they
are doing and maybe we can link to several in that section to show
other approaches?
I would love it, To see a bunch or repos and see how its done And will share our repo too, but its too Amateurish now, Once i refactor to use best practices and see some examples will share it.
Needs to get some additional information. Namely; that even though the name “CentOS” is created by group_by, the variables in a “host_vars/CentOS” file will only be loaded when there is a [CentOS] section with the server name in the inventory file.
plus:
- hosts: all
tasks:
- group_by key=${ansible_distribution}
Needs to be:
- hosts: all
tasks:
- group_by: key=${ansible_distribution}
Needs to get some additional information. Namely; that even though the name
"CentOS" is created by group_by, the variables in a "host_vars/CentOS" file
will only be loaded when there is a [CentOS] section with the server name in
the inventory file.
Thanks, didn't think of that -- we may want to streamline that at some point.
plus:
- hosts: all
tasks:
- group_by key=${ansible_distribution}
Needs to be:
- hosts: all
tasks:
- group_by: key=${ansible_distribution}
forgot the colon in the "free hand"
Nice, I also noticed I typoed "ntp" vs "ntpd" in a few places.
Maybe out of scope for this particular document, but I think it would be useful to capture different scenarios. Probably easiest to crowd-source it, different people could document how they structure things for their organizations (not so different from the content in this thread). This way, a reader could say, “Ah, scenario X matches my context the closest, I’ll do mine in a similar way”.
I’m not quite sure where to put this type of content.
It is great to be able to change inventory files. A problem we run into is that we use different ssh keys for staging and production. Is it possible to specify an ssh key as a variable in an inventory file so we can use different keys like that?
What I probably should do is write a local_action task that calls “ssh-add -l” and checks if the required keys are present, and if not, bails out. That way, it’s clear to the user that the failure was because keys hadn’t been loaded yet. Something like:
name: ensure keys are present in local ssh-agent
local_action: shell ssh-add -l | grep --silent $item
with_items: ssh_key_fingerprints