Variables Ansible : choisir l'emplacement approprié
15 mars 2022
- Catégories
- DevOps & SRE
- Tags
- Infrastructure
- Ansible
- IaC
- YAML [plus][moins]
Ne ratez pas nos articles sur l'open source, le big data et les systèmes distribués, fréquence faible d’un email tous les deux mois.
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 :
- valeurs de la ligne de commande (par exemple,
-u mon_utilisateur
, ce ne sont pas des variables) - valeurs par défaut des rôles (définies dans
role/defaults/main.yml
) - fichiers inventory ou script
group_vars
- inventory
group_vars/all
- playbook
group_vars/all
- inventory
group_vars/*
- playbook
group_vars/*
- fichiers inventory ou script
host_vars
- inventory
host_vars/*
- playbook
host_vars/*
facts
de l’host /set_facts
en cache- variables play
- play
vars_prompt
- play
vars_files
- variables de rôle (définies dans
role/vars/main.yml
) - variables de bloc (seulement pour les tâches d’un bloc)
- variables de tâche (uniquement pour une tâche)
include_vars
set_facts
/ variables enregistrées (registered
)- paramètres de rôle (et
include_role
) - paramètres inclus (
include
) - 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 :
- valeurs par défaut des rôles (définies dans
role/defaults/main.yml
) - 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.
- valeurs par défaut des rôles (définies dans
role/defaults/main.yml
) - 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 :
- valeurs par défaut des rôles (définies dans
role/defaults/main.yml
) - inventory
group_vars/*
- 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.