New "Best Practices" documentation, please help me review

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:

https://github.com/ansible/ansible/blob/devel/docsite/rst/bestpractices.rst

A few key things I am trying to show.

* 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!

--Michael

Nice to read, thank you!

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?

Cheers,

elektrokokke

It does the latter, it applies tags to what is included so they can be
filtered by tag with "--tags" if you want.

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?

-sv

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:

https://coderwall.com/p/ur8qnw?i=1&p=2&q=sort%3Ascore+desc&t[]=ansible

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.

But obviously every site is totally different.

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:

    install-software/
       install-tomcat.paybook.yaml
       install-nginx.playbook.yaml

    tasks/

    accounting/
       templates/
       accounting-all.playbook
       accounting-tomcat.playbook.yaml
       accounting-ngix.playbook.yaml
       accounting-oracle.playbook.yaml
       tasks/
         accounting-tomcat.tasks.yaml
         accounting-oracle.tasks.yaml

    logistics/
       logisctics-all.playbook.yaml
       logistics-nginx.playbook.yaml
       logistics-nginx.tasks.yaml

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.

Yeah, it was kind of a starting point. If I make a very detailed
structure, it's hard on the simpler environments.

If I go too simple, it's hard to grok for the more complex environments.

I'm thinking maybe we explain it somewhat like I have it now, and then
maybe have an "alternate structure suggestions" or something after...

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.

K

This is great, my 2c.

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 :slight_smile: i learn by examples), Let me know if this is reasonable.

Regards,–
Kavin Kankeshwar

This is great, my 2c.

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 :slight_smile: 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?

This is great, my 2c.

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 :slight_smile: 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.

The “group_by” example: https://github.com/ansible/ansible/blob/devel/docsite/rst/bestpractices.rst#operating-system-and-distribution-variance

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}

forgot the colon in the “free hand” :wink:

The "group_by" example:
https://github.com/ansible/ansible/blob/devel/docsite/rst/bestpractices.rst#operating-system-and-distribution-variance

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" :wink:

Nice, I also noticed I typoed "ntp" vs "ntpd" in a few places.

I’d say, The whole concept makes less sense to use with this. :slight_smile:

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.

Lorin

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?

Lorin

Not presently, normally you have to use ssh-agent anyway.

Yeah, ssh-agent is the right way to go.

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

Take care,

Lorin