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:

  1. command line values ​​(eg -u my_userthese are not variables)
  2. role standards (defined in role/defaults/main.yml)
  3. inventory file or script group_vars
  4. stock group_vars/all
  5. playbook group_vars/all
  6. stock group_vars/*
  7. playbook group_vars/*
  8. inventory file or script host_vars
  9. stock host_vars/*
  10. playbook host_vars/*
  11. host facts / cached set_facts
  12. play whose
  13. play vars_prompt
  14. play vars_files
  15. role whose (defined in role/vars/main.yml)
  16. block whose (only for data in blocks)
  17. task whose (only for the task)
  18. include_vars
  19. set_facts / registered whose
  20. role (and include_role) params
  21. include params
  22. 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:

  1. role defaults (defined in role/defaults/main.yml)
  2. 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.

  1. role defaults (defined in role/defaults/main.yml)
  2. 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 servicebto 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:

  1. role defaults (defined in role/defaults/main.yml)
  2. inventory group_vars/*
  3. 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

Leave a Reply