Table des matières

Ansible Best-Practices

La meilleure pratique pour utiliser Ansible est de comprendre la philosophie qui sous-tend la conception d'Ansible. Vous pouvez remarquer que presque toutes les meilleures pratiques d'Ansible ont une sorte de relation avec la philosophie qui sous-tend Ansible.

Tout d'abord, Ansible réduit la complexité grâce à la conception d'outils, et il encourage également les utilisateurs à faire de même.

La philosophie cruciale suivante de la conception d'Ansible est l'optimisation du contenu pour la lisibilité. Si le contenu d'Ansible est correctement optimisé, il pourrait également servir de documentation pour l'automatisation du flux de travail.

La recommandation la plus importante dans la philosophie d'Ansible est l'adéquation des diverses approches.

Ansible possède des capacités substantielles d'adaptation à divers environnements et flux de travail tout en assurant la gestion de tâches d'automatisation complexes. Par conséquent, les utilisateurs doivent continuer à expérimenter différentes approches pour tirer le meilleur parti de la puissance et de la simplicité d'Ansible.

Organisation du contenu

La section suivante présente l’un des nombreux moyens possibles d’organiser le contenu d’un playbook.

Un moyen crucial d’organiser le contenu de votre Playbook est la fonction d’organisation «Rôles» d’Ansible.

Vous devriez prendre le temps de lire et de comprendre la documentation sur les rôles qui est disponible ici: Rôles.

Contrôle de version

Utilisez le contrôle de version.

Conservez vos playbooks et votre fichier d’inventaire dans git (https://gitlab.accor.net), et validez-les lorsque vous les modifiez.

Ainsi, vous disposez d’un journal d’audit décrivant quand et pourquoi vous avez modifié les règles qui automatisent votre infrastructure.

Structure du répertoire

Le niveau supérieur du répertoire contiendrait des fichiers et des répertoires comme ceci :

production                # inventory file for production servers
staging                   # inventory file for staging environment

group_vars/
   group1.yml             # here we assign variables to particular groups
   group2.yml
host_vars/
   hostname1.yml          # here we assign variables to particular systems
   hostname2.yml

library/                  # if any custom modules, put them here (optional)
module_utils/             # if any custom module_utils to support modules, put them here (optional)
filter_plugins/           # if any custom filter plugins, put them here (optional)

site.yml                  # master playbook

roles/
    common/               # this hierarchy represents a "role"
        tasks/            #
            main.yml      #  <-- tasks file can include smaller files if warranted
        handlers/         #
            main.yml      #  <-- handlers file
        templates/        #  <-- files for use with the template resource
            ntp.conf.j2   #  <------- templates end in .j2
        files/            #
            bar.txt       #  <-- files for use with the copy resource
            foo.sh        #  <-- script files for use with the script resource
        vars/             #
            main.yml      #  <-- variables associated with this role
        defaults/         #
            main.yml      #  <-- default lower priority variables for this role
        meta/             #
            main.yml      #  <-- role dependencies
        library/          # roles can also include custom modules
        module_utils/     # roles can also include custom module_utils
        lookup_plugins/   # or other types of plugins, like lookup in this case

    webtier/              # same kind of structure as "common" was above, done for the webtier role
    monitoring/           # ""
    fooapp/               # ""

Rester simple : Keep It Simple

Lorsque vous pouvez faire quelque chose, faites-le simplement. N'utilisez pas simultanément toutes les fonctionnalités d'Ansible.

Utilisez ce qui fonctionne pour vous. Par exemple, vous n'aurez probablement pas besoin de vars, vars_files, vars_prompt et –extra-vars en même temps, tout en utilisant également un fichier d'inventaire externe.

Si quelque chose vous semble compliqué, ce qui est probablement le cas, c'est peut être une bonne occasion de simplifier les choses.

Écrire les rôles avec un sens technique

Dès qu’on commence à écrire un rôle Ansible, la tentation est grande de fourrer dedans un peu tout pour avoir une espèce de boîte à outils réutilisable.

En réalité, il faut essayer de séparer le contenu des rôles par objet technique : un rôle “MongoDB”, un rôle “HAProxy”, un rôle “Tomcat” et utiliser ensuite la glue fournie par les playbooks pour faire l’assemblage simplement et rapidement.

Cette séparation vous permet de regrouper au sein du même rôle toutes les tâches qui peuvent être effectuées pour le composant concerné : l’installation, la configuration, le démarrage, l’arrêt, la maintenance, la mise à jour… et seulement de ce composant.

Si votre code doit toucher à un autre composant technique, essayez de le mettre dans un autre rôle dès que possible. Et si vous tenez absolument à orchestrer ces tâches depuis un rôle, écrivez un rôle transverse qui va faire appel aux différentes étapes de vos rôles techniques.

L’objectif premier est de bien séparer les actions qui sont effectuées dans un rôle donné, diminuant ainsi ses dépendances, et le nombre de variables dont il a besoin. Le second objectif est bien évidemment la ré-utilisabilité, qui est primordiale, pour tout code.

Utiliser la syntaxe YAML et pas la syntaxe Ansible

Ansible vous permet d’utiliser un mélange entre deux syntaxes lorsque vous rédigez votre code. Vous pouvez soit utiliser du YAML pur :

- name: add user testuser1
  user:
    name: testuser1
    state: present
    groups: wheel

Ou vous pouvez aussi utiliser la syntaxe hybride YAML et Ansible :

- name: add user testuser1
  user: name=testuser1 state=present groups=wheel

Ces deux exemples sont rigoureusement identiques en terme de description Ansible.

Cette syntaxe est pratique, mais elle oblige à une certaine gymnastique avant d’arriver à faire fonctionner une tâche, surtout quand celle-ci est complexe.

La bonne pratique consiste à toujours utiliser la syntaxe YAML pour éviter la syntaxe hybride avec les =: elle permet une détection d’erreurs un peu plus tôt, et augmente la lisibilité de votre code Ansible.

Espaces et commentaires

L’utilisation généreuse des espaces pour dissocier les choses et l’utilisation de commentaires (commençant par «#») sont encouragées ! (Vraiment !)

Toujours mentionner l'état : state

Le paramètre ‘state’ est facultatif pour beaucoup de modules. Qu'il s'agisse de ‘state=present’ ou de ‘state=absent’, il est toujours préférable de laisser ce paramètre dans vos playbooks pour le rendre clair, d'autant plus que certains modules prennent en charge des états supplémentaires.

Nommez toujours les tâches

Il est possible de ne pas indiquer le nom pour une tâche donnée, bien qu'il soit recommandé de fournir une description de la raison pour laquelle quelque chose est fait.

Ce nom est affiché lorsque le livre de lecture est exécuté.

Documenter les variables

Ansible supporte la surcharge de variables suivant l’endroit où vous les déclarez.

Dans la documentation officielle, on explique la priorité des déclarations des variables comme suit :

   role defaults [1]
   inventory vars [2]
   inventory group_vars
   inventory host_vars
   playbook group_vars
   playbook host_vars
   host facts
   play vars
   play vars_prompt
   play vars_files
   registered vars
   set_facts
   role and include vars
   block vars (only for tasks in block)
   task vars (only for the task)
   extra vars (always win precedence)

Comme on peut le voir, la liste est particulièrement fournie et vous permet de surcharger une variable n’importe où, grosso modo.

Du coup, il faut faire attention :

Variation du système d'exploitation et de la distribution

Lorsque vous traitez avec un paramètre différent entre deux systèmes d'exploitation différents, utilisez le module group_by pour le gérer.

---
 
 - name: talk to all hosts just so we can learn about them
   hosts: all
   tasks:
     - name: Classify hosts depending on their OS distribution
       group_by:
         key: os_{{ ansible_facts['distribution'] }}
 
 # now just on the CentOS hosts...
 
 - hosts: os_RedHat
   gather_facts: False
   tasks:
     - # tasks that only happen on RedHat go here

Cela renverra tous les systèmes dans un groupe dynamique basé sur le nom du système d'exploitation.

Si des paramètres spécifiques à un groupe sont nécessaires, vous pouvez également le faire.

Par exemple:

---
# file: group_vars/all
asdf: 10
 
---
# file: group_vars/os_RedHat
asdf: 42

Dans l’exemple ci-dessus, les machines RedHat obtiennent la valeur «42» pour asdf, mais les autres machines obtiennent «10». Cela peut être utilisé non seulement pour définir des variables, mais également pour appliquer certains rôles à certains systèmes uniquement.

Sinon, si seules des variables sont nécessaires:

- hosts: all
  tasks:
    - name: Set OS distribution dependant variables
      include_vars: "os_{{ ansible_facts['distribution'] }}.yml"
    - debug:
        var: asdf

Cela fournira des variables basées sur le type d'OS.

Données sensibles dans une sortie accessible

L'accent mis sur les meilleures pratiques de sécurité d'Ansible est également une préoccupation importante pour les utilisateurs. Les utilisateurs ne doivent pas exposer de données sensibles dans les sorties standard. Si vous utilisez le module “template-” et que le fichier contient des mots de passe et d'autres données sensibles, vous ne voudriez pas qu'ils figurent dans la sortie.

Dans ce cas, vous pouvez utiliser l'option “no_log”. En ajoutant l'option “no_log-” à une tâche, il n'y aura pas de journal de la sortie.

Prenons par exemple le livre de jeu suivant,

TASK [This fails] **********************************************
fatal: [127.0.0.1]: FAILED! => {"changed": true,
"cmd": "echo This is my secret password && false",
"delta": "000.003950", "end": "2019-09-27 1452.194098",
"msg": "non-zero return code", "rc": 1,
"start": "2019-09-27 1452.190148", "stderr": "",
"stderr_lines": [], "stdout": "This is my secret password",
"stdout_lines": ["This is my secret password"]}
TASK [This fails] ***********************************************
fatal: [127.0.0.1]: FAILED! => {"censored": "the output has been
hidden due to the fact that 'no_log: true' was specified for this
result", "changed": true}

Vous pouvez également utiliser la “ansible-vault” pour la sécurité des données sensibles dans le playbook et les rôles.