Gestion de la configuration 101 : Écriture de playbooks Ansible

Introduction

En bref, la gestion de la configuration des serveurs (également appelée couramment automatisation IT) est une solution permettant de transformer l’administration de votre infrastructure en un ensemble de scripts de provisionnement pouvant être versionnés et réutilisés facilement. Cela peut grandement améliorer l’intégrité de n’importe quelle infrastructure serveur au fil du temps.

Dans un guide précédent, nous avons discuté des principaux avantages de la mise en œuvre d’une stratégie de gestion de la configuration pour votre infrastructure serveur, du fonctionnement des outils de gestion de la configuration et des éléments typiques de ces outils.

Cette partie de la série vous guidera à travers le processus d’automatisation du provisionnement des serveurs en utilisant Ansible, un outil de gestion de la configuration qui fournit un cadre d’automatisation complet et des capacités d’orchestration, tout en maintenant un objectif de simplicité ultime et de minimalisme. Nous nous concentrerons sur la terminologie, la syntaxe et les fonctionnalités nécessaires pour créer un exemple simplifié permettant de automatiser entièrement le déploiement d’un serveur web Ubuntu 18.04 à l’aide d’Apache.

La liste suivante contient toutes les étapes que nous devons automatiser afin d’atteindre notre objectif:

  1. Mettre à jour le cache apt
  2. Installer Apache
  3. Créer un répertoire racine de document personnalisé
  4. Placez un fichier index.html dans le répertoire de document personnalisé
  5. Appliquez un modèle pour configurer notre hôte virtuel personnalisé
  6. Redémarrez Apache

Nous commencerons par jeter un coup d’œil à la terminologie utilisée par Ansible, suivi d’une vue d’ensemble des principales fonctionnalités du langage pouvant être utilisées pour écrire des playbooks. À la fin du guide, vous trouverez le contenu d’un exemple complet de provisionnement pour automatiser les étapes décrites pour configurer Apache sur Ubuntu 18.04.

Note: ce guide vise à vous initier au langage Ansible et à la rédaction de playbooks pour automatiser la provision de votre serveur. Pour une vue plus introductive d’Ansible, incluant les étapes nécessaires à l’installation et à la prise en main de cet outil, ainsi que la manière d’exécuter des commandes et des playbooks Ansible, consultez notre guide Comment Installer et Configurer Ansible sur Ubuntu 18.04.

Commencer

Avant de passer à une vue plus pratique d’Ansible, il est important que nous nous familiarisions avec la terminologie et les concepts importants introduits par cet outil.

Terminologie

La liste suivante contient un aperçu rapide des termes les plus pertinents utilisés par Ansible :

  • Nœud de Contrôle : la machine où Ansible est installé, responsable de l’exécution de la provision sur les serveurs que vous gérez.
  • Inventaire : un fichier INI contenant des informations sur les serveurs que vous gérez.
  • Playbook : un fichier YAML contenant une série de procédures devant être automatisées.
  • Tâche : un bloc qui définit une seule procédure à exécuter, par exemple : installer un package.
  • Module : un module abstrait généralement une tâche système, comme la gestion des packages ou la création et modification de fichiers. Ansible dispose d’une multitude de modules intégrés, mais vous pouvez également en créer des personnalisés.
  • Rôle : un ensemble de playbooks, de modèles et d’autres fichiers connexes, organisés de manière prédéfinie pour faciliter la réutilisation et le partage.
  • Play : une provision exécutée du début à la fin est appelée un play.
  • Facts : des variables globales contenant des informations sur le système, telles que les interfaces réseau ou le système d’exploitation.
  • Handlers : utilisés pour déclencher des changements d’état du service, comme le redémarrage ou le rechargement d’un service.

Format de Tâche

A task defines a single automated step that should be executed by Ansible. It typically involves the usage of a module or the execution of a raw command. This is how a task looks:

- name: This is a task
  apt: name=vim state=latest

La partie name est en fait facultative, mais recommandée, car elle apparaît dans la sortie de la provision lorsque la tâche est exécutée. La partie apt est un module intégré à Ansible qui abstrait la gestion des paquets sur les distributions basées sur Debian. Cette tâche d’exemple indique à Ansible que le paquet vim devrait avoir son état changé en latest, ce qui entraînera l’installation de ce paquet si ce n’est pas déjà fait.

Format du Playbook

Les playbooks sont des fichiers YAML contenant une série de directives pour automatiser la provision d’un serveur. L’exemple suivant est un playbook simple qui effectue deux tâches : met à jour le cache apt et installe ensuite vim :

---
- hosts: all
  become: true
  tasks:
     - name: Update apt-cache 
       apt: update_cache=yes

     - name: Install Vim
       apt: name=vim state=latest

YAML repose sur l’indentation pour sérialiser les structures de données. Pour cette raison, lors de l’écriture de playbooks et surtout lors de la copie d’exemples, vous devez être particulièrement attentif à maintenir l’indentation correcte.

Avant la fin de ce guide, nous verrons un exemple plus concret d’un playbook, expliqué en détail. La prochaine section vous donnera un aperçu des éléments et fonctionnalités les plus importants qui peuvent être utilisés pour écrire des playbooks Ansible.

Écriture de Playbooks

Maintenant que vous êtes familiarisé avec la terminologie de base et le format général des playbooks et des tâches dans Ansible, nous allons apprendre quelques fonctionnalités des playbooks qui peuvent nous aider à créer des automatisations plus polyvalentes.

Travailler avec des variables

Il existe différentes façons de définir des variables dans Ansible. La manière la plus simple est d’utiliser la section vars d’un playbook. L’exemple ci-dessous définit une variable package qui est ensuite utilisée dans une tâche :

---
- hosts: all
  become: true
  vars:
     package: vim
  tasks:
     - name: Install Package
       apt: name={{ package }} state=latest

La variable package a une portée globale, ce qui signifie qu’elle peut être accédée à partir de n’importe quel point de la provision, même à partir des fichiers inclus et des modèles.

Utilisation des boucles

Les boucles sont généralement utilisées pour répéter une tâche en utilisant différentes valeurs d’entrée. Par exemple, au lieu de créer 10 tâches pour installer 10 packages différents, vous pouvez créer une seule tâche et utiliser une boucle pour répéter la tâche avec tous les packages différents que vous voulez installer.

Pour créer une boucle au sein d’une tâche, incluez l’option with_items avec un tableau de valeurs. Le contenu peut être accédé via la variable de boucle item, comme le montre l’exemple ci-dessous :

- name: Install Packages
  apt: name={{ item }} state=latest
  with_items:
     - vim
     - git
     - curl  

Vous pouvez également utiliser une variable de tableau pour définir vos éléments :

---
- hosts: all
  become: true
  vars:
     packages: [ 'vim', 'git', 'curl' ]
  tasks:
     - name: Install Package
       apt: name={{ item }} state=latest
       with_items: "{{ packages }}"

Utilisation des conditionnelles

Les conditionnelles peuvent être utilisées pour décider dynamiquement si une tâche doit être exécutée ou non, en fonction d’une variable ou d’une sortie d’une commande, par exemple.

L’exemple suivant ne va arrêter que les systèmes basés sur Debian :

- name: Shutdown Debian Based Systems
  command: /sbin/shutdown -t now
  when: ansible_os_family == "Debian"

La conditionnelle when reçoit en argument une expression à évaluer. La tâche n’est exécutée que si l’expression est évaluée à true. Dans notre exemple, nous avons testé un fait pour vérifier si le système d’exploitation est de la famille Debian.

A common use case for conditionals in IT automation is when the execution of a task depends on the output of a command. With Ansible, the way we implement this is by registering a variable to hold the results of a command execution, and then testing this variable in a subsequent task. We can test for the command’s exit status (if failed or successful). We can also check for specific contents inside the output, although this might require the usage of regex expressions and string parsing commands.

L’exemple suivant montre deux tâches conditionnelles basées sur la sortie d’une commande php -v. Nous allons tester le statut de sortie de la commande, car nous savons qu’elle échouera à s’exécuter si PHP n’est pas installé sur ce serveur. La partie ignore_errors de la tâche est importante pour s’assurer que la provision continue même lorsque la commande échoue à s’exécuter.

- name: Check if PHP is installed
  register: php_installed
  command: php -v
  ignore_errors: true

- name: This task is only executed if PHP is installed
  debug: var=php_install
  when: php_installed|success
  
- name: This task is only executed if PHP is NOT installed
  debug: msg='PHP is NOT installed'
  when: php_installed|failed

Le module debug utilisé ici est un module utile pour afficher le contenu des variables ou des messages de débogage. Il peut soit imprimer une chaîne (lors de l’utilisation de l’argument msg) soit imprimer le contenu d’une variable (lors de l’utilisation de l’argument var).

Travailler avec les modèles

Les modèles sont généralement utilisés pour configurer des fichiers de configuration, permettant l’utilisation de variables et d’autres fonctionnalités destinées à rendre ces fichiers plus polyvalents et réutilisables. Ansible utilise le moteur de modèle Jinja2.

L’exemple suivant est un modèle pour configurer un hôte virtuel Apache, en utilisant une variable pour définir le répertoire de documents de cet hôte :

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot {{ doc_root }}

    <Directory {{ doc_root }}>
        AllowOverride All
        Require all granted
    </Directory>
</VirtualHost>

Le module intégré template est utilisé pour appliquer le modèle à partir d’une tâche. Si vous avez nommé le fichier de modèle ci-dessus vhost.tpl et que vous l’avez placé dans le même répertoire que votre playbook, voici comment vous appliqueriez le modèle pour remplacer l’hôte virtuel Apache par défaut :

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf

Définition et déclenchement des gestionnaires

Les gestionnaires sont utilisés pour déclencher un changement d’état dans un service, tel qu’un redémarrage ou un arrêt. Bien qu’ils puissent sembler assez similaires aux tâches régulières, les gestionnaires ne sont exécutés que lorsqu’ils ont été préalablement déclenchés par une directive notify dans une tâche. Ils sont généralement définis sous forme de tableau dans une section handlers du playbook, mais ils peuvent également se trouver dans des fichiers séparés.

Prenons en considération notre exemple précédent d’utilisation de modèle, où nous avons configuré un hôte virtuel Apache. Si vous voulez vous assurer qu’Apache est redémarré après un changement d’hôte virtuel, vous devez d’abord créer un gestionnaire pour le service Apache. Voici comment les gestionnaires sont définis dans un playbook :

handlers:
    - name: restart apache
      service: name=apache2 state=restarted
    
    - name: other handler
      service: name=other state=restarted

La directive name ici est importante car elle sera l’identifiant unique de ce gestionnaire. Pour déclencher ce gestionnaire à partir d’une tâche, vous devez utiliser l’option notify :

- name: Change default Apache virtual host
  template: 
    src: vhost.tpl
    dest: /etc/apache2/sites-available/000-default.conf
  notify: restart apache

Nous avons vu quelques-unes des fonctionnalités les plus importantes que vous pouvez utiliser pour commencer à écrire des playbooks Ansible. Dans la prochaine section, nous plongerons dans un exemple plus concret d’un playbook qui automatisera l’installation et la configuration d’Apache sur Ubuntu.

Exemple de playbook

Jetons maintenant un coup d’œil à un playbook qui automatisera l’installation d’un serveur web Apache sur un système Ubuntu 18.04, comme discuté dans l’introduction de ce guide.

L’exemple complet, incluant le fichier modèle pour la configuration d’Apache et un fichier HTML à servir par le serveur web, peut être trouvé sur Github. Le dossier contient également un fichier Vagrantfile qui vous permet de tester le playbook dans une configuration simplifiée, en utilisant une machine virtuelle gérée par Vagrant.

Contenu du playbook

Le contenu complet du playbook est disponible ici pour votre commodité :

playbook.yml
  1. ---
  2. - hosts: all
  3. become: true
  4. vars:
  5. doc_root: /var/www/example
  6. tasks:
  7. - name: Update apt
  8. apt: update_cache=yes
  9. - name: Install Apache
  10. apt: name=apache2 state=latest
  11. - name: Create custom document root
  12. file: path={{ doc_root }} state=directory owner=www-data group=www-data
  13. - name: Set up HTML file
  14. copy: src=index.html dest={{ doc_root }}/index.html owner=www-data group=www-data mode=0644
  15. - name: Set up Apache virtual host file
  16. template: src=vhost.tpl dest=/etc/apache2/sites-available/000-default.conf
  17. notify: restart apache
  18. handlers:
  19. - name: restart apache
  20. service: name=apache2 state=restarted

Examinons chaque partie de ce playbook en détail :

hôtes: tous
Le playbook commence en indiquant qu’il doit être appliqué à tous les hôtes de votre inventaire (hôtes: tous). Il est possible de restreindre l’exécution du playbook à un hôte spécifique ou à un groupe d’hôtes. Cette option peut être écrasée au moment de l’exécution.

devenir: vrai
La partie devenir: vrai indique à Ansible d’utiliser l’élévation de privilèges (sudo) pour exécuter toutes les tâches de ce playbook. Cette option peut être écrasée tâche par tâche.

vars
Définit une variable, doc_root, qui est ensuite utilisée dans une tâche. Cette section pourrait contenir plusieurs variables.

tâches
La section où les tâches réelles sont définies. La première tâche met à jour le cache apt, et la deuxième tâche installe le paquet apache2.

La troisième tâche utilise le module intégré fichier pour créer un répertoire qui servira de racine de document. Ce module peut être utilisé pour gérer les fichiers et répertoires.

La quatrième tâche utilise le module copie pour copier un fichier local sur le serveur distant. Nous copions un fichier HTML simple pour être servi en tant que site web hébergé par Apache.

gestionnaires
Enfin, nous avons la section gestionnaires, où les services sont déclarés. Nous définissons le gestionnaire redémarrer apache qui est notifié à partir de la quatrième tâche, où le modèle Apache est appliqué.

Exécution d’un playbook

Une fois que vous avez téléchargé le contenu de ce playbook sur votre nœud de contrôle Ansible, vous pouvez utiliser ansible-playbook pour l’exécuter sur un ou plusieurs nœuds de votre inventaire. La commande suivante exécutera le playbook sur tous les hôtes de votre fichier d’inventaire par défaut, en utilisant l’authentification par paire de clés SSH pour se connecter en tant qu’utilisateur système actuel:

  1. ansible-playbook playbook.yml

Vous pouvez également utiliser -l pour limiter l’exécution à un seul hôte ou à un groupe d’hôtes de votre inventaire:

  1. ansible-playbook -l host_or_group playbook.yml

Si vous devez spécifier un utilisateur SSH différent pour vous connecter au serveur distant, vous pouvez inclure l’argument -u utilisateur à cette commande:

  1. ansible-playbook -l host_or_group playbook.yml -u remote-user

Pour plus d’informations sur la façon d’exécuter des commandes et des playbooks Ansible, veuillez vous référer à notre guide sur Comment Installer et Configurer Ansible sur Ubuntu 18.04.

Conclusion

Ansible est un outil d’automatisation IT minimaliste qui présente une courbe d’apprentissage faible, utilisant YAML pour ses scripts de provisionnement. Il dispose d’un grand nombre de modules intégrés qui peuvent être utilisés pour abstraire des tâches telles que l’installation de paquets et le travail avec des modèles. Ses exigences en infrastructure simplifiées et son langage simple peuvent convenir à ceux qui commencent avec la gestion de configuration. Cependant, il peut manquer certaines fonctionnalités avancées que l’on peut trouver avec des outils plus complexes comme Puppet et Chef.

Dans la prochaine partie de cette série, nous verrons un aperçu pratique de Puppet, un outil populaire et bien établi de gestion de configuration qui utilise un DSL personnalisé expressif et puissant basé sur Ruby pour écrire des scripts de provisionnement.

Source:
https://www.digitalocean.com/community/tutorials/configuration-management-101-writing-ansible-playbooks