18 sept. 2019

[Ansible] Bonnes pratiques

Ce billet se base sur l'article suivant: https://www.ansible.com/blog/ansible-best-practices-essentials
dans les gros titres. Cependant je me suis permis d'ajouter des remarques personnelles. Selon mon expérience et la compréhension que j'ai eu. Si vous pensez que je fais fausse route n'hésitez pas à commenter.
 ------------

La complexité tue la productivité

Ansible indique par ce titre que ce n'est pas un simple slogan marketing qu'ils avancent. Ils prétendent qu'ils se sont efforcé de réduire la complexité dans la façon dont ils ont créer les outils Ansible. Ils encouragent les utilisateurs à faire pareil, c'est à dire simplifier ce que l'utilisateur automatise.

Optimiser ses contenus Ansible

C'est à dire :
  • l'organisation de la structure des dossiers
  • le classement des machines (qualification, pré-production, production)
  • gestion fine des variables associées (group_vars)
  • la hiérarchisation et le classement des playbooks et roles la plus fine
 Si cela est fait correctement dés le début de votre projet, votre code peut devenir la documentation de votre cycle d'automatisation.

En gros : privilégier le moins de code possible. Eviter le plus possible la redondance de rôle et de playbook. Les playbooks doivent être commun pour tous les environnements (ppd, prd, etc). Seule les variables doivent différer.

Penser "déclaratif"

Ansible est déclaratif, ce n'est pas un langage de programmation. Si on tente de le tordre pour faire de la programmation avec des playbooks YAML, nous allons vite être limité et allons créer de la complexité. Les playbooks YAML n'a pas été conçu pour ça.

Voir Ansible comme un couteau suisse du Devops

Ansible est capable de gérer de

1) Nommer ses playbooks et tâches.

Toujours nommer les playbooks et tâches. Mettre des descriptions compréhensibles par un humain.

Prenons l'exemple ci-dessous :
- hosts: web
  tasks:
  - yum:
      name: httpd
      state: latest

  - service:
      name: httpd
      state: started
      enabled: yes

PLAY [web] ******************************************************

TASK [setup] ****************************************************
ok: [web1]

TASK [yum] ******************************************************
ok: [web1]

TASK [service] **************************************************
ok: [web1]
Sans connaitre exactements les plays il n'est pas possible en regardant les logs quels sont les actions effectuées, seule les modules et les hosts sont précisés.

Maintenant prenons l'exemple ci-dessous :
- hosts: web
  name: installs and starts apache
  tasks:
    - name: install apache packages
      yum:
        name: httpd
        state: latest

    - name: starts apache service
      service:
        name: httpd
        state: started
        enabled: yes
PLAY [install and starts apache] ***********************************

TASK [setup] *******************************************************
ok: [web1]

TASK [install apache packages] *************************************
ok: [web1]

TASK [starts apache service] ***************************************
ok: [web1]
C'est tout de suite plus claire. On comprend en regardant d'un seul coup d'oeil ce qu'il se passe.

2) Utiliser des préfixes et des noms compréhensibles avec les variables

Ansible dispose d'un système de variable assez puissant qui collecte des metadonnées provenant de différentes sources. Cependant il faut déployer beaucoup d'effort faire simple et le plus transparent pour l'utilisateur.

Le système de variable a été intentionnellement limité pour faciliter la compréhension et le débogage.

Cependant il faut bien nommer ses variables pour éviter toute confusion.

Exemple :
sshd_port: 22
apache_port: 80
tomcat_port: 8080

En préfixant avec le nom du produit, protocole ou usage, on voit dans cet exemple tout de suite de quoi on parle.

3) Utiliser la syntaxe YAML native

Le lanceur de playbook Ansible est essentiellement un analyseur YAML avec nue logique supplémentaire telle que des raccourcis en ligne de commande.
Bien que pratique lors de la création d'un playbook, ce style de formatage réduit la lisibilité.

Il est donc recommandé d'éviter l'utilisation de ce genre de raccourci (même avec le style "plié" YAML).

Voici un exemple de tâche tuilisant le raccourci clé=valeur (key=value) :
- name: install telegraf
  yum:
    name: telegraf-{{ telegraf_version }} state=present update_cache=yes disable_gpg_check=yes enablerepo=telegraf
  notify: restart telegraf

- name: configure telegraf
  template: src=telegraf.conf.j2 dest=/etc/telegraf/telegraf.conf
  notify: restart telegraf

- name: start telegraf
  service: name=telegraf state=started enabled=yes
Voici la même chose en YAML natif :
- name: install telegraf
  yum: telegraf-{{ telegraf_version }}
    state: present
    update_cache: yes
    disable_gpg_check: yes
    enablerepo: telegraf
  notify: restart telegraf

- name: configure telegraf
  template:
    src: telegraf.conf.j2
    dest: /etc/telegraf/telegraf.conf
  notify: restart telegraf

- name: start telegraf
  service:
    name: telegraf
    state: started
    enabled: yes
Nous pourrions nous dire qu'il y a plus de ligne en YAML. Cependant des lignes sont plus courtes et réduisent le scrolling horizontal.
La lisibilité est meilleure et en plus il y a une coloration syntaxique dans la plus part des éditeurs (VIM, atom, VSCode, etc)

De plus les raccourcis sont me semble-t-il dépréciés par Ansible, pure hypotèse: donc potentiellement retiré dans la version majeurs à venir.

4) Utiliser les modules avant les Run Commands

Les "Run Commands" sont les modules command, shell, raw et script que les utilisateurs peuvent activer lors de l'exécution de playbook ansible.
C'est un mécanisme qui fonctionne et permet d'obtenir des résultats mais il convient de les utilisé parcimonie et en dernier recours. Les raisons sont nombreuses et variées.

Exemple :
- name: Change file ownership and group
  command: chown foo:foo /etc/foo.conf

- name: Change permissions
  command: chmod 0644 /etc/foo.conf



Peut être remplacer par le module file :
- name: Change file ownership, group and permissions
  file:
    path: /etc/foo.conf
    owner: foo
    group: foo
    mode: '0644'

La surutilisation de "Run Commands" est commune à ceux qui débutent avec Ansible et qui ne sont pas familiers des modules. Ils utilisent le module shell pour lancer une commande Bash qu'ils connaissent déjà.
Cela fonctionne au début et cela peut être utile quand on a des scripts Shell de déploiement à porter sur Ansible. Mais cela nuit à l'utilité à la pertinence de l'utilisation d'Ansible.

Si on utilise Ansible autant utiliser les modules que celui-ci offre. Si effectivement il n'y a pas de module pour ce que l'on veut faire, nous pouvons nous tourner vers les "Run Commands". Mais en dernier recours. D'ailleurs la meilleurs façon de savoir s'il existe un module est de consulter la documentation: https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

Pour les plus chevronnés qui n'ont pas trouver leur bonheur parmi les modules existant, on peut considérer la possibilité de développer son propre module et le partager à la communauté si celui-ci peut être partagé.  http://docs.ansible.com/ansible/developing_modules.html


5) Faire le ménage dans les messages de déboggage

Il est parfois utile d'utiliser le mode debug d'ansible pour par exemple afficher le contenu d'une variable pendant l'exécution d'un playbook. Cependant lorsqu'il y a trop de message cela peut être désagréable. Ansible conseille d'utiliser le paramètre "verbosity" qui permet de choisir le volume de message que l'on souhaite.
Exemple :
- debug:
   msg: "This always displays"

- debug:
   msg: "This only displays with ansible-playbook -vv+"
   verbosity: 2

 Désormais l'utilisateur du playbook ansible peut choisir s'il veut ou non avoir le message de debug.


3 commentaires:

Différences majeures entre Red Hat 6, 7, 8 et 9

Quelles sont les différences majeures entre RHEL 6, 7, 8 et 9 ? Système de fichiers RHEL 6: Par défaut : ext4. Autres : ext2, ext3 supportés...