Ansible - Bonnes pratiques et ressources

Partie 5 et fin

Et voici le dernier article de cette série consacrée à l'outil de déploiement Ansible. Vous y trouverez essentiellement des ressources utiles, bonnes pratiques acquises avec l'expérience, etc.

Bonnes pratiques et ressources

Quelques bonnes pratiques

La documentation officielle Ansible en propose une très bonne liste. Nous allons en reprendre quelques unes ici. J'ajouterai également celles apprises avec l'expérience.

Organisation de l'arborescence

Ansible recommande deux versions, personnellement j'applique celle-ci :

./
    inventories/
        production/
            hosts # le fichier d'inventaire
            group_vars/
                group1.yml
                group2.yml
            hosts_vars/
                host1.yml
                host2.yml
        preprod/
            hosts # le fichier d'inventaire
            group_vars/
                group1.yml
                group2.yml
            hosts_vars/
                host1.yml
                host2.yml
    playbook1.yml
    playbook2.yml
    roles/
        role1/
        role2/
        role3/

Cette proposition répond aussi à la question fréquente qui se demande comment différencier les hosts de production des preproductions : l'idéal est de créer des inventaires séparés. Ceci vous permet aussi de gérer des variables spécifiques via le group_vars/host_vars.

Les handlers pour les actions post

On l'a vu dans l'article sur les playbooks, lorsqu'une action doit être déclenchée après une tâche, il convient d'utiliser l'instruction notify dans la tâche avec le nom d'un handler tel que défini dans handlers/main.yml.

Par exemple nous modifions la configuration d'Apache HTTPD et rechargeons le service pour prise en compte.

Dans le fichier tasks/main.yml du rôle :

- name: "deploy httpd.conf"
  template:
    src: etc_httpd_conf_httpd.conf.j2
    dest: /etc/httpd/conf/httpd.conf
  notify: reload apache

Dans handlers/main.yml

- name: reload apache
  service:
    name: httpd
    state: reloaded

Il est toujours possible de tester le résultat d'une tâche pour en déclencher une autre, mais cela n'est pas recommandé par l'outil.

Les rôles sont réutilisables, les playbooks jetables

Un playbook peut être écrit pour un besoin donné et être jeté lorsqu'il n'est plus nécessaire. Si le code est prévu pour être réutilisé, il convient de l'écrire sous la forme d'un rôle pour pouvoir l'appeler dans diverses playbooks sans avoir à tout réécrire.

Organiser son inventaire et grouper

Comme dit dans l'article sur l'inventaire, l'organisation de celui-ci va conditionner comment vous écrirez votre code. Essayez de schématiser votre infrasture par type de serveur, rôle applicatif, ou encore par localisation. Cela vous permettra des exécutions ciblées faciles et évitera de retoucher le code si un cas de figure n'a pas été prévu.

Assurez-vous de la compatibilité OS

Les distributions Linux peuvent avoir des différences entre elles, pensez à tester en premier lieu avec le module assert que l'environnement attaqué est compatible avec votre rôle. (exemple : yum versus apt pour la gestion de paquets, ou encore le nommage de paquets qui peut diverger)

Toujours nommer ses tâches

L'instruction name est vitale pour s'y retrouver dans le code !

Faire simple

Un code facile a maintenir c'est un code simple, n'essayez pas de faire des choses complexes inutilement. Si quelque chose devient trop compliqué, ça peut être l'occasion de le simplifier. Un code trop complexe risque aussi d'entraîner une perte de maîtrise et la peur de l'exécuter parce qu'on ne sait pas ce qu'il va faire. C'est tout l'opposé de ce pourquoi Ansible a été construit : avoir toujours le même résultat.

Ne pas penser shell

Les modules Ansible font nativement des contrôles et des actions pré et post : inutile de leur en faire faire en plus. N'abusez-pas non plus du module shell par facilité, demandez-vous toujours si un module existe pour l'action que vous attendez. Le code shell arbitraire nécessite de gérer l'idempotence soit-même là où Ansible est nativement conçu pour le faire.

Versionner le code

Le code Ansible est comme n'importe quel autre programme, il convient de versionner son code avec un gestionnaire de sources tel que Git. Ce combo vous permettra notamment de rentrer dans une approche GitOps où un commit sur un inventaire peut déclencher un déploiement automatisé via l'outillage approprié.

Respecter l'idempotence

Comme expliqué dans l'introduction, Ansible est nativement idempotent : c'est à dire que le résultat sera toujours le même, et que l'action ne sera pas refaite si elle l'a déjà été (exemple : il vérifira les permissions d'un fichier avant de bêtement appliquer celles demandées par le code). Assurez-vous que votre utilisation des modules respecte ce principe pour justifier l'état "changed" d'une tâche.

Exemples :

  • Une tâche shell qui exécute un rapide ensemble de commandes pour alimenter une variable est-elle réellement un changement ?
  • Une tâche qui exécute une requête en base de données doit être aussi capable d'alimenter les contrôles de statut changed_when et failed_when. (compter le nombre d'enregs touchés par un update, vérifier si l'insert est possible avant de le faire, etc)

Un principe essentiel à retenir est que le récapitulatif à la fin d'une exécution Ansible doit être représentatif de ce qui a vraiment été changé ou non.

Nommage des templates et fichiers

Une pratique que j'ai rapidement apprise, je nomme toujours les fichiers à déployer ou les templates selon l'emplacement où ils devront aller.

Ainsi, le fichier de config Apache HTTPD sous forme de template sera nommé : etc_httpd_conf_httpd.conf.j2; pour être déployé dans /etc/httpd/conf/httpd.conf. Cela permet de savoir au premier coup d'oeil où sera déployé votre template.

Ansible Lint pour contrôler son code

Ansible Lint est un outil complémentaire proposé dans le cadre du repository Ansible Galaxy pour contrôler la qualité du code et proposer des axes d'amélioration ou de bonnes pratiques.

Cet outil peut être activé comme étape de pre-commit lorsque le code est versionné par Git qui lancera le contrôle avant d'appliquer le commit. Je vous recommande vivement de l'utiliser, c'est un excellent outil pour apprendre à avoir de bons réflexes.

Mitogen pour accélérer Ansible

Mitogen est une bibliothèque Python qui permet d'optimiser les programmes utilisant l'auto réplication comme Ansible. En effet, l'un des soucis d'Ansible est qu'il peut donner l'impression d'être lent car il va ouvrir et fermer une connexion SSH à chaque tâche. Le plugin Mitogen permet de maintenir la session et accélère grandement les déploiements réalisés avec ce dernier. Il permet également de réduire la consommation CPU lors de l'exécution, rendant un déploiement plus transparent d'un point de vue utilisation de ressources.

Conclusion

Voilà qui termine cette série de billets dédiée à Ansible. J'espère que cela vous aura permis de découvrir cet outil ou d'approfondir celles-ci. Si vous voyez d'autres bonnes pratiques ou astuces à partager, n'hésitez-pas.