Support Ukrain
Adaltas logoAdaltasAdaltas logoAdaltas
Variables Ansible : choisir l'emplacement approprié

Variables Ansible : choisir l'emplacement approprié

HERMAND Xavier

By HERMAND Xavier

15 mars 2022

Catégories
DevOps & SRE
Tags
Ansible
Infrastructure
YAML
IaC
[plus][moins]

Définir des variables pour vos playbooks et rôles Ansible peut devenir un défi à mesure que votre projet se développe.

Naviguer la documentation Ansible est source de questionnements et de confusion :

  1. valeurs de la ligne de commande (par exemple, -u mon_utilisateur, ce ne sont pas des variables)
  2. valeurs par défaut des rôles (définies dans role/defaults/main.yml)
  3. fichiers inventory ou script group_vars
  4. inventory group_vars/all
  5. playbook group_vars/all
  6. inventory group_vars/*
  7. playbook group_vars/*
  8. fichiers inventory ou script host_vars
  9. inventory host_vars/*
  10. playbook host_vars/*
  11. facts de l’host / set_facts en cache
  12. variables play
  13. play vars_prompt
  14. play vars_files
  15. variables de rôle (définies dans role/vars/main.yml)
  16. variables de bloc (seulement pour les tâches d’un bloc)
  17. variables de tâche (uniquement pour une tâche)
  18. include_vars
  19. set_facts / variables enregistrées (registered)
  20. paramètres de rôle (et include_role)
  21. paramètres inclus (include)
  22. paramètres supplémentaires (par exemple, -e "user=my_user") (toujours prioritaires).

Il y a 22 endroits différents où vous pouvez placer vos variables ! A mesure que votre project mature et se complexifie, cela peut devenir compliqué.

Définir son propre sous-ensemble d’emplacements de variables

La méthode simple

Chaque fois que vous pensez à une variable, l’endroit où elle est définie devrait être évident. Si ce n’est pas le cas, cela signifie peut-être que vous dispersez vos variables à trop d’endroits. Commencez par quelque chose de simple, par exemple en ayant seulement 2 endroits où vos variables peuvent être définies :

  1. valeurs par défaut des rôles (définies dans role/defaults/main.yml)
  2. paramètres de rôle (et include_role)

roles/serviceA/default.yml : ce fichier définit toutes les variables requises par le rôle, avec quelques valeurs par défaut. Notez comment il est possible de commenter les variables qui sont requises, mais pour lesquelles nous ne voulons pas fournir de valeur par défaut. En faisant cela, nous documentons chaque variable dont le rôle a besoin.

servicea_log_dir : /var/log/servicea
# servicea_user : /var/log/servicea
servicea_autorestart : yes

serviceA.yml : ce fichier est le playbook dans lequel le rôle est appelé. Nous y mettons notre configuration personnalisée.

- hosts : groupa
  rôles :
  - role : serviceA
    vars :
      servicea_user : gollum
      servicea_autorestart : no

Nous avons choisi 2 emplacements pour notre projet : les valeurs par défaut des rôles, et les paramètres de rôle. Il est ainsi facile de savoir où trouver notre variable. Cette solution devrait fonctionner dans la plupart des situations.

La méthode plus générale

Prenons un autre sous-ensemble d’emplacements.

  1. valeurs par défaut des rôles (définies dans role/defaults/main.yml)
  2. inventory group_vars/*

roles/serviceA/default.yml : valeurs par défaut des rôles, définis de la même manière que dans l’exemple précédent.

servicea_log_dir: /var/log/servicea
# servicea_user:
servicea_autorestart: yes

inventory/group_vars/servicea.yml : ces variables vont être associées au groupe appelé servicea.

servicea_user: gollum
servicea_autorestart: no

Il faut ensuite associer correctement le rôle aux hôtes où pour lesquels sont défini les variables (rappel : à l’exécution, les variables sont au final associées à un hôte : il n’y a pas de groupes ou de rôle par défaut, seulement des variables d’hôte). Le playbook :

- hosts: servicea
  roles:
  - role: serviceA

Maintenant, disons que nous voulons avoir plusieurs rôles, servicea et serviceb, à exécuter sur un groupe appelé par exemple worker. Nous pourrions écrire la configuration personnalisée pour les deux services (servicea et serviceb) dans un seul fichier : inventory/group_vars/worker.yml ; cependant il ne sera pas vraiment évident de savoir où trouver vos variables personnalisées.

A la place, nous pouvons avoir 1 groupe par service, donc 1 fichier de configuration par service dans le dossier group_vars (servicea.yml et serviceb.yml). Nous associons ensuite les hôtes worker au groupe de nos différents services. inventory/hosts :

[worker]
worker01.local
worker02.local
worker03.local
worker04.local

[servicea:children]
worker

[serviceb:children]
worker

La mauvaise méthode

Prenons les 2 exemples précédents et mélangeons-les. Nous choisissons 3 emplacements :

  1. valeurs par défaut des rôles (définies dans role/defaults/main.yml)
  2. inventory group_vars/*
  3. paramètres de rôle (et include_role)

Disons que nous voulons modifier la variable servicea_log_dir. Nous ne pouvons pas changer la valeur par défaut du rôle, car nous voulons notre propre valeur personnalisée. Maintenant, devons-nous la changer dans le group_vars ou dans les paramètres de rôle ? Les deux fonctionnent, et il n’y a aucun moyen de savoir quel emplacement choisir, à moins qu’il y ait une logique spécifique derrière. Ce fonctionnement n’est pas correct car nous voulons garder les choses simples.

Pensez à gitops

Lorsque vous choisissez les quelques emplacements que vous utiliserez, pensez à l’effet que ce choix aura sur le versionning de votre code.

La méthodologie gitops peut vous aider. En bref, vous voulez diviser votre code en 2 dépôts : votre dépôt avec le code, et votre dépôt avec les opérations.

Appliqué à Ansible, le dépôt avec le code est l’endroit où vous versionnez vos rôles ou vos collections Ansible. Le dépôt avec les opérations est l’endroit où vous versionnez tout ce qui est spécifique à une instance de votre code, à savoir votre inventory et vos variables personnalisées.

Si vous utilisez la méthode simple, vous devrez versionner vos playbooks dans votre dépôt ops, car ils contiennent vos variables personnalisées. Si vous utilisez la deuxième méthode que nous avons décrite, où chaque variable personnalisée se trouve dans le group_vars/* de l’inventory, vous pouvez ne versionner que l’inventory dans votre dépôt ops.

Ce qui importe, c’est qu’il soit possible de séparer le code générique et les propriétés propres à une instance. Par exemple, stocker des variables personnalisées dans le dossier vars d’un rôle (ex : roles/servicea/vars/main.yml) n’est pas correct.

Si vous pensez à une variable et que vous savez avec certitude où elle a été définie, alors vous faites probablement les choses correctement.

Canada - Maroc - France

International locations

10 rue de la Kasbah
2393 Rabbat
Canada

Nous sommes une équipe passionnée par l'Open Source, le Big Data et les technologies associées telles que le Cloud, le Data Engineering, la Data Science le DevOps…

Nous fournissons à nos clients un savoir faire reconnu sur la manière d'utiliser les technologies pour convertir leurs cas d'usage en projets exploités en production, sur la façon de réduire les coûts et d'accélérer les livraisons de nouvelles fonctionnalités.

Si vous appréciez la qualité de nos publications, nous vous invitons à nous contacter en vue de coopérer ensemble.