How to share group_vars between different inventories in Ansible?
The simple option here (and what we do) is simply symlink generic group vars files around.
For instance we might have a generic role for something like NGINX and then a few concrete use cases for that role. In this case we create a group vars file that uses the NGINX role for each concrete use case and then simply symlink those group vars files into the appropriate folders.
Our project folder structure then might look something like this (drastically simplified):
.
├── inventories
│ ├── bar-dev
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── dev.yml -> ../../shared/dev.yml
│ │ └── inventory
│ ├── bar-prod
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── prod.yml -> ../../shared/prod.yml
│ │ └── inventory
│ ├── bar-test
│ │ ├── group_vars
│ │ │ ├── bar.yml -> ../../shared/bar.yml
│ │ │ └── test.yml -> ../../shared/test.yml
│ │ └── inventory
│ ├── foo-dev
│ │ ├── group_vars
│ │ │ ├── dev.yml -> ../../shared/dev.yml
│ │ │ └── foo.yml -> ../../shared/foo.yml
│ │ └── inventory
│ ├── foo-prod
│ │ ├── group_vars
│ │ │ ├── foo.yml -> ../../shared/foo.yml
│ │ │ └── prod.yml -> ../../shared/prod.yml
│ │ └── inventory
│ ├── foo-test
│ │ ├── group_vars
│ │ │ ├── foo.yml -> ../../shared/foo.yml
│ │ │ └── test.yml -> ../../shared/test.yml
│ │ └── inventory
│ └── shared
│ ├── bar.yml
│ ├── dev.yml
│ ├── foo.yml
│ ├── prod.yml
│ └── test.yml
└── roles
└── nginx
├── defaults
│ └── main.yml
├── meta
│ └── main.yml
├── tasks
│ └── main.yml
└── templates
└── main.yml
Now our inventory files can have the hosts use these shared group vars simply by putting the hosts in the correct groups.
I scrapped the idea of following Ansible's recommendation. Now one year later, I am convinced that Ansible's recommendation is not useful for my requirements. Instead I think it is important to share as much as possible among different stages.
Now I put all inventories in the same directory:
production.ini
reference.ini
And I take care that each inventory defines a group including all hosts with the name of the stage.
The file production.ini
has the group production
:
[production:children]
all_production_hosts
And the file reference.ini
has the group reference
:
[reference:children]
all_reference_hosts
I have just one group_vars
directory in which I define a file for every staging group:
group_vars/production.yml
group_vars/reference.yml
And each file defines a stage
variable. The file production.yml
defines this:
---
stage: production
And the file reference.yml
defines that:
---
stage: reference
This makes it possible to share everything else between production and reference. But the hosts are completely different. By using the right inventory the playbook runs either on production or on reference hosts:
ansible-playbook -i production.ini site.yml
ansible-playbook -i reference.ini site.yml
If it is necessary for the site.yml
or the roles to behave slightly different in the production and reference environment, they can use conditions using the stage
variable. But I try to avoid even that. Because it is better to move all differences into equivalent definitions in the staging files production.yml
and reference.yml
.
For example, if the group_vars/all.yml
defines some users:
users:
- alice
- bob
- mallory
And I want to create the users in both environments, but I want to exclude mallory
from the production environment, I can define a new group called effective_users
. In the reference.yml
it is identical to the users
list:
effective_users: >-
{{ users }}
But in the production.yml
I can exclude mallory
:
effective_users: >-
{{ users | difference(['mallory']) }}
The playbook or the roles do not need to distinguish between the two stages, they can simply use the group effective_users
. The group contains automatically the right list of users simply by selecting the inventory.