
Ansible variables: choosing the right location
Defining variables for your Ansible playbooks and roles can become challenging as your project grows.
Browsing in Ansible documentationthe diversity of Ansible variable location is confusing to say the least:
- command line values (eg
-u my_user
these are not variables) - role standards (defined in
role/defaults/main.yml
) - inventory file or script
group_vars
- stock
group_vars/all
- playbook
group_vars/all
- stock
group_vars/*
- playbook
group_vars/*
- inventory file or script
host_vars
- stock
host_vars/*
- playbook
host_vars/*
- host
facts
/ cachedset_facts
- play whose
- play
vars_prompt
- play
vars_files
- role whose (defined in
role/vars/main.yml
) - block whose (only for data in blocks)
- task whose (only for the task)
include_vars
set_facts
/ registered whose- role (and
include_role
) params - include params
- extra vars (for example,
-e "user=my_user"
)(always takes precedence)
There are 22 different places where you can store your variables! As your code evolves and becomes more complex, it can become messy.
Define your own subset of variable locations
The simple way
When you think of a variable, it should be obvious where it is defined. If not, you might be spreading your variables in too many places. Start with something simple, like having only two places where your variables can be defined:
- role defaults (defined in role/defaults/main.yml)
- role (and include_role) parameters
roles/serviceA/default.yml
: this file defines All variables required by the role, with some default values. Note how we can comment out variables that are required, but for which we don't want to specify a default value. By doing so, we document every variable that the role needs.
servicea_log_dir: /var/log/servicea
servicea_autorestart: yes
serviceA.yml
: this file is the playbook where the role is called. We put ours custom configuration there.
- hosts: groupa
roles:
- role: serviceA
vars:
servicea_user: gollum
servicea_autorestart: no
We chose 2 locations for our project: role defaults, et role params. It is easy to know where to find our variable. It should work in most situations.
A more general way
Let's have another subset of places.
- role defaults (defined in role/defaults/main.yml)
- inventory group_vars/*
roles/serviceA/default.yml
: role default settings, defined in the same as in the previous example.
servicea_log_dir: /var/log/servicea
servicea_autorestart: yes
inventory/group_vars/servicea.yml
: these variables will be associated with the group called servicea
servicea_user: gollum
servicea_autorestart: no
It is then required that the role is correctly associated with the hosts where you have defined the variables (reminder: at runtime, variables are ultimately associated with a host: there are no groups or role defaults, only host variables). The Playbook:
- hosts: servicea
roles:
- role: serviceA
Now let's say we want multiple roles, servicea
and serviceb
to run on a group called for example worker
. We could write the custom configuration for both services (servicea
and serviceb
) in a single file: inventory/group_vars/worker.yml
; but then it's really not obvious where to find your custom variables.
Instead we can have 1 group per service, so 1 configuration file per service i group_vars
folder (servicea.yml
and serviceb.yml
). We then associate to worker
hosts the group of our various services. inventory/hosts
:
[worker]
worker01.local
worker02.local
worker03.local
worker04.local
[servicea:children]
worker
[serviceb:children]
worker
A wrong way
Let's just take the previous 2 examples and mix them. We choose 3 places:
- role defaults (defined in role/defaults/main.yml)
- inventory group_vars/*
- role (and include_role) parameters
Let's say we want to modify servicea_log_dir
variable. We can't change the role default variable, because we want our own custom value. Now we change that in group_vars
or in the role parameters? Both work, and there's no way to know which location you'd choose, unless there's a specific logic behind it. This is not correct and we want to keep it simple.
Think gitops
When choosing some locations to use, consider the effect it will have on your code version management.
Gitops method can help you. In short, you want to split your code into 2 repositories: your code repository and your ops repository.
If you apply it to Ansible, your code repository is where you version your roles or your Ansible collections. Your ops repository is where you version everything specific to an instance of your code; namely your layer and custom variables.
When using the simple way, you need to version your playbooks in your ops repository, because they contain your custom variables. When you use the second method we described, where each custom variable is in its own inventory group, you can only version the inventory in your ops repository.
What is important is that it should be possible to split the generic code and the properties that are right for an instance. For example storing custom variables in vars
folder for a role (eg roles/servicea/vars/main.yml
) is not correct.
If you think of any variable and know for sure where it has been defined, then you are probably doing things right.
#Ansible #variables #choosing #location
Source link