I was happy to see “roles” when I came back to Ansible after a few months, but i’ve been struggling with how to apply them. I think this is partly because of cognitive dissonance between my mental model and the current terminology.
In my mind, any particular role that a server may fill (and it may fill more than one), in turn requires one or more “features” or “feature-sets” in order to be able to fulfill that role. In other words, I think of a heirarchy that looks like this;
- appstack_X
** server_n
*** role_a
**** feature_A
**** feature_E
**** feature_O
*** role_b
**** feature_A
**** feature_B
**** feature_G
Anyone else gone through this thought process,or organize their configs like this?
Yes. I’m only new to ansible but am seriously struggling. The playbooks I can get my head around but the roles are proving very painful. I thought the idea might be to switch features on/off for each host via variables? Would that work?
[Trivial annoyance: i hate the way it requires a bunch of folders with just one file in them each]
[Related to that sidenote: the folders are going to have lonely main.ymls for quite a while since the only apparent use of a file in the same directory is to be ‘included’ from main.yml? Have I got that wrong?]
Recently I have changed my Ansible set-up based on roles. I have a very similar dependency structure as yours:
host1 → profile1, profile2
host2 → profile2, profile3
profile1 → state1, state2
profile2 → state2, state3
…
Both profiles and states are roles, but I separate them into two roles directories. I then use role dependencies between profiles and states (and states and states). A playbook simply ties hosts to profile roles.
A few thing I ran into:
- I needed to use a trick to make sure each state role is run only once. See [1].
- No parameters can be passed to state roles; global variables only. (I use a third role category named “configs” with roles that take parameters.)
Small annoyances:
- Tasks that are skipped because the role already ran still show up in the log.
Other than that, it works great!
I would give details, but I am still working on it. May post more when I am satisfied – or someone bugs me
[1] https://groups.google.com/d/msg/ansible-project/nd4wMLsb0Jw/7-svzpNpTIQJ
Regards,
Joost
roles are there to make reusable units of non trivial set of tasks,
sometimes its just easier to create a simple tasklist and use include:.
If it is becoming 'painful' its a sign of trying to put square peg in round
hole. Ansible is designed to be simple, also it is very flexible and can be
used in many different ways. It leaves organization up to you but sometimes
this becomes an issue, specially if coming from other tools from which you
got into the habit of complexity.
I recommend taking a step back at this point, go back to you goal and think
of simpler approaches.
for the original poster, you can use roles == features or even a 'wrapper
role' that uses the feature roles as dependencies. I generally equate
'machine roles' == groups and use plays to group 'feature roles'.
I have to agree with Brian – sounds like you are not breaking your problem down into simple enough parts.
The problem with Ansible (and other similar config management / state management tools) is that most people (well, at least me) come in thinking one way about their requirements which isn’t immediately compatible with how the tool was designed and/or works. You have to learn to think about your problems in terms of Ansible (or whatever tool you’re using).
In this case, Ansible is stupidly simple on purpose. However, I’ve been beating my head against it for about 6 months now and am just starting to really ‘get it’. And most of that was me learning how to simplify what I needed to do into smaller and smaller chunks which made sense for Ansible and then how to relate those chunks together.
One of the big things was determining when and where I did certain things within Ansible. You can put things in playbooks or roles or both, but not all will necessarily be good for you. For example I have a role for my NTP configuration. I then have this role applied to all hosts in my top level play list. However, I then ran into a hurdle as all machines need NTP, but there is one machine that must be an NTP server. I first worked on this with having different roles (ntp-client vs ntp-server) but found for my needs that a single ‘ntp’ role would suffice and within that role I then choose one of two different templates (client vs server) based upon whether or not the host was in the ‘ntp server‘ host group. I do want to point out that I could have used two different roles but I decided against that for reasons that make sense within my hosting environment. My point is, I had many options on how to put the Ansible building blocks together and it took me a while to figure out the best way to put them together for my needs. There was a lot of trial and error. But I’ve finally got there.
Another thing I did was to use the ‘group_by’ functionality to build host groups on the fly. Then I use those groupings to determine when to apply different roles or even different parts of specific roles. So, originally I just had roles with a single ‘tasks/main.yml’. And I tried to keep it that way. But after working with Ansible for a while and reviewing what I was trying to do, I now have roles with lots of task files that get included within tasks/main.yml. So a lot of my roles use a lot of ‘include/when’ patterns based around groupings I’ve built on the fly via ‘group_by’.
So, TL;DR – keep pounding on it, keep trying different code arrangements, keep trying to break your requirements into smaller and simpler parts. Also, you have to figure out how best to put all the pieces together. Such as some people don’t use role dependencies, but some people love them. Eventually you’ll get it. And I would say that as you use Ansible expect that you will end up re-writing your entire Ansible code base a couple of times until you find a layout that works best for you.
Thx
Gopher.
Yes and no…
In the case above I would consider that feature_A is a separate role but is a dependency of role_a and role_b…
In my case I have a “common” role that performs a number of trivial tasks. Each task is a separate, distinct, task so it has it’s own file in role/common/tasks/… The main.yml includes all of those tasks within that role, but order in this case is irrelevant.
So for your example I would have the following structure…
role/role_a/tasks/
feature_E
feature_O
role/role_b/tasks/
feature_B
feature_G
role/feature_a/tasks/
feature_A
and then in both role/role_a/meta and role/role_b/meta you would have a main.yml that had
dependencies:
If you later added a role_c using features C, D and F it would not include a dependency for feature_a… I would still have a separate main.yml in role/feature_a/tasks (although I would not use that name) in case I ever wanted to add an additional task to that feature. That way I can write the new task and then modify the main.yml.
I hope that this helps,
Adan
Yes. I'm only new to ansible but am seriously struggling. The playbooks I
can get my head around but the roles are proving very painful. I thought
the idea might be to switch features on/off for each host via variables?
Would that work?
I suggest you look at lots of other people's roles and playbooks.
Roles are just a way to group tasks, handlers, and files/templates they
use, so they are just a basic grouping around normal ansible syntax.
[Trivial annoyance: i hate the way it requires a bunch of folders with
just one file in them each]
Sorry, this will not be changing.
[Related to that sidenote: the folders are going to have lonely main.ymls
for quite a while since the only apparent use of a file in the same
directory is to be 'included' from main.yml? Have I got that wrong?]
You can also put things in the main.yaml.
Both profiles and states are roles, but I separate them into two roles
directories. I then use role dependencies between profiles and states (and
states and states). A playbook simply ties hosts to profile roles.
A few thing I ran into:
* I needed to use a trick to make sure each state role is run only once.
See [1].
Please don't try to make ansible more complex than it actually is. I'm not
even sure what a "profile" or "state role" is, and if I don't know, that's
a problem with someone interpreting ansible to be WAAAAY more complicated
than it should be.
We're talking servers here, not programming.
Simplify. Keep things easy.
I have it as simple as this;
Playbooks
\ server1.yml
\ server2.yml
\ roles/ldap
\ roles/Apache...
And so on, its very simple and its easy to manager
Hi Michael and others,
It could be me explaining wrong, or I could be off the path, but let
me try again. My site playbook is basically only used to tie roles to
host groups. Those roles are specific for our infrastructure, e.g.
setting up our frontend server, backend server, etc. I call those
"profiles". The roles I call "states" are more like shareable
components: setting up Nginx, fail2ban, etc. The dependencies follow
the path: playbook -> profile role -> state roles (-> state roles).
This feels quite natural to me, but I do run into the issues I
described. If this set-up is still too complex I am very interested to
hear about simplifications.
Regards,
Joost
It's cleaner to have the roles explicitly listed up in site.yml .
Then site.yml defines the roles on each host group, and you avoid the
issue with roles running twice when you explicitly define them that way.
You can still have 'states' as you define them just as typical roles, maybe
with a README in there to explain it's a 'building block' role and
needs further config
to be usable (we name those roles base-nginx, base-elasticsearch, etc.
when they don't have a valid config so will need to be tailored to do
be functional).
Having said all that, I do use roles/foo/meta/main.yml to 'autoload'
dependencies sometimes;
there are several of us working on this playbook so it can be helpful.
Mind you, I've got several years of Puppet baggage so 'wiring' modules
together is in
my muscle memory, I'm not sure if that's the Ansible Way..
David,
I’m coming from a similar place in terms of seeing things as roles with features and I’m also just getting started with ansible.
I made a common role considering it as ‘included for all roles and applied conditionally’.
Tasks are included based on group membership, or host in inventory.
I organize the files dir into folders for each task, which each represent “features”.
You can account for configuration differences within tasks based on inventory as well.
Based on ideas in this thread I’m considering breaking as much as I can into “feature” roles, which are added to “functional” roles, and only leaving what is truly common (ie. firewall rules, etc).
I recommend you take a step back and look at the problem from the perspective of your overall Configuration Management (CM) process. For example, what are your configuration items (CIs)? What is your change management process? What is your version control process? First document these processes and then adapt Ansible to fit them. In my experience Ansible is very flexible and can fit whatever process you have in place. I wouldn’t worry about Ansible’s terminology. Roles, Groups, etc. can be whatever you want them to be; they are just arbitrary labels.
The most important thing is to identify your CIs. Then structure your playbooks to manage them. Their level of granularity depends on the level that your CM plan calls for. Each CI should be under version control at the very least. Avoid the mistake of a tool-centric perspective. Focus on good, quality processes and then customize the tools to support them.
–Aaron