Skip to content

Commit

Permalink
Update
Browse files Browse the repository at this point in the history
  • Loading branch information
gfaivre committed Dec 6, 2023
1 parent 33b3031 commit 11511ad
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 18 deletions.
196 changes: 178 additions & 18 deletions content/blog/cours/ansible/ansible-les-playbooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ title: "Ansible - Les playbooks"
date: "2023-12-05"
lastModified: ~
tableOfContent: true
description: "Découverte des playbooks, élément essentiel d'Ansible qui va nous permettre d'organiser et structure nos tâches !"
description: "Découverte des playbooks, élément essentiel d'Ansible qui va nous permettre d'organiser et structurer nos tâches !"
thumbnail: "content/images/blog/thumbnails/ansible-playbooks.jpg"
tags: ["cours", "ansible", "automation", "playbook"]
categories: ["cours"]
Expand All @@ -24,20 +24,20 @@ Disposer d'un **environnement de travail Ansible fonctionnel**, si ça n'est pas

## Introduction

Un playbook Ansible est un élément central pour Ansible puisque c'est dans ce fichier de configuration (écrit en YAML toujours), que l'on va organiser et indiquer quelles actions nous souhaitons faire à Ansible.
Un playbook Ansible est un élément **central** pour Ansible puisque c'est dans ce fichier de configuration (écrit en YAML toujours), que l'on va organiser et indiquer quelles actions nous souhaitons déclencher à Ansible.

Les playbooks décrivent des « tâches » à exécuter sur des groupes de machines décritent dans [les inventaires](/blog/cours/ansible/ansible-les-inventaires-statiques), ils sont écrit à l'aide du format [YAML](https://yaml.org/).
Les playbooks décrivent des « tâches » à exécuter sur des groupes de machines identifiés dans [les inventaires](/blog/cours/ansible/ansible-les-inventaires-statiques), ils sont écrits à l'aide du format [YAML](https://yaml.org/).

!!! info "La syntaxe Yaml"
Yaml est un langage ou plutôt un format qui permet de sérialiser des données afin qu'elles restent lisiblent pour nous. Les données sont organisées sous la forme de paire clé/valeur dans des listes ordonnées, il est de plus en plus utilisé notamment pour les fichiers de configuration.
Yaml est un langage ou plutôt un format, qui permet de sérialiser des données afin qu'elles restent lisiblent pour nous. Les données sont organisées sous la forme de paire clé/valeur dans des listes ordonnées, il est de plus en plus utilisé notamment pour les fichiers de configuration.

## Mise en route
## Les playbooks

Afin de rentrer dans le vif du sujet nous allons écrire un playbook relativement simple utilisant un module que nous avons vu précédemment, le module **ping**. Nous avons en effet vu que les modules Ansible peuvent être utiliser en ligne de commande pour exécuter une tâche ponctuelle mais rappelons que le but d'Ansible est en premier lieu, d'automatiser les choses et donc de les rendres réutilisables !
Afin de rentrer dans le vif du sujet nous allons écrire un playbook relativement simple utilisant un module que nous avons vu précédemment, le module **ping**. Nous avons en effet vu que les modules Ansible peuvent être utilisés en ligne de commande pour exécuter une tâche ponctuelle mais rappelons que le but d'Ansible est en premier lieu, d'**automatiser** les choses et donc de les rendre **réutilisables** !

### Structure générale d'un playbook

Créons un nouveau fichier que nous appelerons `ping.yml` dans notre répertoire de travail (pour rappel de mon côté `workspace/ansible`) contenant:
Créons un nouveau fichier que nous appellerons `example.yml` dans notre répertoire de travail (pour rappel de mon côté `workspace/ansible`) contenant:

```yaml
---
Expand All @@ -50,10 +50,16 @@ Créons un nouveau fichier que nous appelerons `ping.yml` dans notre répertoire
La structure YAML permet une compréhension relativement aisée du contenu, on identifiera ainsi:
- Une clé principale appelée `hosts` permettant de définir les « hôtes » (machines distantes) concernées par les tâches qui vont suivre;
- Une sous clé `tasks` permettant de définir les différentes « tâches » ou actions que nous souhaitons déclencher vers nos machines distantes.
- Une clé principale appelée `hosts` permettant de définir les « hôtes » ou plutôt les machines concernées par les tâches qui vont suivre (identifiées par leur groupe d'appartenance);
- Une clé `tasks` permettant de définir les différentes « tâches » ou actions que nous souhaitons déclencher sur nos machines.

Rappelez-vous nous pouvons traduire les instructions suivantes sous forme de tableaux:
**Un bloc ainsi défini est appelé un « play »**.

!!! info "---"
Vous l'aurez noté, les playbooks que nous rédigeons commencent tous avec trois tirets `---`, ceux-ci marquent en effet en syntaxe Yaml, le début du document, ils sont donc indispensables à l'interprétation du fichier.
Ils permettent entre autres d'utiliser des directives en entêtes de fichier ou de disposer de plusieurs flux yaml dans un même fichier (le début de chaque flux étant indiqué par ces trois tirets).

Rappelez-vous nous pouvons traduire les instructions suivantes sous forme de **tableaux**:

```php
array (
Expand Down Expand Up @@ -83,7 +89,7 @@ On constate encore plus aisément sous cette forme que la clé `tasks` permet de

Nous avons déjà vu les commandes `ansible` et `ansible-inventory` au tour de `ansible-playbook`

En exécutant cette commande `ansible-playbook ping.yml -i inventories` vous devriez obtenir la sortie suivante ou équivalente (si tout se passe bien).
En exécutant cette commande `ansible-playbook example.yml -i inventories` vous devriez obtenir la sortie suivante ou équivalente (si tout se passe bien).

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-ping.png">
Expand All @@ -92,18 +98,19 @@ En exécutant cette commande `ansible-playbook ping.yml -i inventories` vous dev
</figcaption>
</figure>

Nous venons donc de faire appel au module ping mais à l'intérieur d'un playbook. Ce que nous avons en retour et une sortie type d'Ansible sur laquelle on peut remarquer quelques informations toujours intéressantes (tout en bas) avec notamment:
Nous venons donc de faire appel au module ping mais **à l'intérieur d'un playbook**. Ce que nous avons en retour et une sortie type d'Ansible sur laquelle on peut remarquer quelques informations toujours intéressantes (tout en bas) avec notamment:

- `ok`: Le nombre de tâches (tasks) qui se sont correctement exécutées;
- `changed`: Le nombre de changements opérés sur nos machines cibles;
- `unreachable`: Le nombre de machine injoignable (par soucis de réseau par exemple);
- `unreachable`: Le nombre de machines injoignables (par soucis de réseau par exemple);
- `failed`: Le nombre de tâches en erreur;
- `skipped`: Le nombre de tâches qui ont été ignorées (par exemple si une tâches ne remplie pas certaines conditions prédéfinies).

Il est bon de noté également qu'un playbook peut contenir plusieurs « plays » nous pouvons donc avoir des tâches attribuées à différents groupe cible comme ceci:
### Les notions de « play » et de « tasks »

Il est bon de noté également qu'un playbook peut contenir plusieurs « plays » nous pouvons donc avoir des tâches attribuées à différents groupes cible comme ceci:

```yaml
# in file ping.yml
---
- hosts: webservers
Expand All @@ -119,18 +126,24 @@ Il est bon de noté également qu'un playbook peut contenir plusieurs « plays
path: /etc/hosts
```

Nous avons dans ce cas de figure deux groupes concernés chacun par une « tâche »:
<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-groups.jpg">
<figcaption>
<span class="figure__legend">Playbook contenant deux « plays ».</span>
</figcaption>
</figure>

Nous avons dans ce cas de figure deux groupes chacun concerné par une « tâche »:

- Le groupe `webservers` (contenant donc 2 machines) sur lequel nous exécutons le module ping;
- Le groupe `dbservers` (contenant également 2 machines) sur lequel nous exécutons le module `stat`.

!!! info "Le module stat"
Le module stat permet d'exécuter la commande système `stat` sur un fichier du serveur cible. Il prends différents paramètres que l'on peut retrouver sur la [documentation officielle](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/stat_module.html) dont le paramètre `path` qui lui est obligatoire.

Rappelez-vous également qu'un « plays » peut avoir à exécuter plusieurs tâches les unes à la suite des autres, exemple:
Rappelez-vous également qu'un « play » peut exécuter plusieurs tâches les unes à la suite des autres, exemple:

```yaml
# in file ping.yml
---
- hosts: webservers
Expand All @@ -150,8 +163,155 @@ Rappelez-vous également qu'un « plays » peut avoir à exécuter plusieurs tâ

Vous devriez, en jouant votre playbook (`ansible-playbook ping -i inventories`) obtenir une sortie équivalente à:

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-tasks.jpg">
<figcaption>
<span class="figure__legend">Playbook contenant deux « plays » et plusieurs « tasks ».</span>
</figcaption>
</figure>

À la différence de nos premières tâches, l'utilisation du module `shell` a entrainé une modification de l'état des deux serveurs membres du groupe `webservers` qu'ansible nous confirme à l'aide de son retour `changed`.

### Visualiser les machines ciblées

Lorsque l'on dispose de playbook assez longs, il peut-être interressant de vérifier la liste des hôtes concernés, c'est faisable à l'aide de la commande `ansible-playbook ping.yml -i inventories --list-host`.

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-list-host.gif">
<figcaption>
<span class="figure__legend">Lister les hôtes concernés par un playbook.</span>
</figcaption>
</figure>

Il est également possible de lister les tâches avec l'option `--list-tasks` et bien évidemment de combiner ces deux options `ansible-playbook ping.yml -i inventories --list-tasks --list-hosts`.

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-list-tasks-hosts.jpg">
<figcaption>
<span class="figure__legend">Lister les hôtes et les tâches concernés par un playbook.</span>
</figcaption>
</figure>

Vous aurez également remarqué la présence d'une information `[TAGS]` très utile dont nous parlerons par la suite ;)

## Les tâches

Nous avons vu les principes fondamentaux du fonctionnements des « tasks » avec Ansible, mais celle-ci peuvent être **plus complexes** que celles que nous avons pu voir jusqu'à présent.
Afin de s'en rendre compte nous allons déployer un serveur web Nginx sur nos instances web.

Nous allons ajouter une tâches dédiée dans un nouveau playbook que nous appelerons `webservers.yml` et qui contiendra les instructions suivantes:

```yaml
---
- hosts: webservers
tasks:
- name: Install Nginx web server
ansible.builtin.apt:
name: nginx
update_cache: yes
state: present
```

En l'exécutant (`ansible-playbook webservers.yml -i inventories`) vous devriez obtenir la sortie ci-dessous, Ansible nous indiquant qu'il a effectué une modification sur nos machines distantes:

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-apt.jpg">
<figcaption>
<span class="figure__legend">Installation d'Nginx avec Ansible.</span>
</figcaption>
</figure>

On notera l'utilisation du module `apt` (attention, utilisable bien évidemment uniquement avec les distributions basées sur Debian) accompagné de plusieurs paramètres;

- `name`: le nom du paquet à installer
- `update_cache`: Indique qu'il faut effectuer une mise à jour de l'index des paquets avant l'installation.
- `state`: « L'état » dans lequel nous souhaitons avoir le paquet installé (present, absent, latest...)

### L'escalade de privilèges

Avec cette tâche d'installation nous touchons une autre problématique qui est celle de la gestion des droits et notamment la modification de manière globale l'état d'un système, ce qui relève normalement de la compétence du compte `root`, super administrateur des systèmes à base UNIX.

Si nous n'avons pas rencontré de problème jusqu'à présent c'est parce que nous utilisons un [lazy Ansible](/blog/cours/ansible/ansible-environnement-cle-en-main) pré-configuré avec certaines directives dans le fichier de configuration d'Ansible dont nous reparlerons un peu plus tard.

Il est toutefois possible le cas échéant, d'indiquer au niveau d'une tâche que celle-ci réclame des droits d'administrateur et qu'il faut déclencher une escalade de privilèges. Cela se fait en utilisant des clés réservées comme ci-dessous (en reprenant la tâche d'installation Nginx):

```yaml
---
- hosts: webservers
remote_user: debian
tasks:
- name: Ensure Nginx service is started
service:
name: nginx
state: started
become: yes
become_user: root # This is the default value, so it is not needed here
```

**On remarquera les clés:**

- `remote_user`: Précisant l'utilisateur avec lequel se connecter à la machine;
- `become`: Indiquant s'il faut déclencher une escalade de privilèges;
- `become_user`: Indiquant le nom du compte utilisateur vers lequel faire l'escalade (Par défaut **root**).

Le mécanisme utilisé par Ansible pour faire son escalade est par défaut la commande `sudo`, il est possible de modifier ce comportement avec la clé `become_method`.

### Organiser ses tâches

Nous avons vu que chaque « play » peut contenir plusieurs tâches, il faut savoir que celles-ci sont exécutées dans l'ordre dans lequel elles apparaissent et sur l'ensemble des machines qui correspondent à leur domaine d'application (un **groupe** ou une **machine**).
Le but de chacune de ces tâches est d'exécuter un module (nous en avons déjà vu plusieurs, **ping**, **stat**, **apt**, **shell**), chaque module se devant d'être [idempotent](https://fr.wikipedia.org/wiki/Idempotence) garantissant ainsi que peu importe le nombre de fois ou il sera exécuté il produira toujours le même résultat si ses paramètres demeurent inchangés.

Il est important que chaque tâche dispose d'une clé `name` fournissant des instructions claires sur son rôle (**pensez à la maintenance**).

Ceci-dit il est bon de savoir que nos tâches peuvent être organisées de différentes manières et notamment en utilisant les différentes sections que l'on peut trouver dans un playbook:

- `pre_tasks`: Contient les tâches à exécuter en premier;
- `roles`: Indiquant une liste de rôles à utiliser dans notre « play » (Nous verrons cette notion plus tard);
- `post_tasks`: Contenant les tâches à exécuter en dernier;
- `handlers`: Contenant des tâches déclenchées à la fin de chaque bloc ou section de tâches en fonction de certains évènements (Nous verrons cette notion plus tard).

#### La section pre_tasks

Elle correspond à une exécution conditionnelle d'un bloc de code **AVANT** de lancer le « play », elle peut être chargée soit de vérifier des pré-requis soit de valider un état.

Souvenez-vous au moment d'installer notre paquet Nginx nous avions ajouté le paramètre `update_cache` afin de mettre à jour l'index des paquets. Mais nous avons une autre option qui se présente, plutôt que de faire figurer cette option sur chaque appel au module `apt` que nous aurons dans notre playbook, nous pouvons gérer la mise à jour du cache de paquets avant de le jouer.

**Modifions notre playbook `webservers.yml` de la façon suivante:**

```yaml
---
- hosts: webservers
pre_tasks:
- name: Updating APT cache index
ansible.builtin.apt:
update_cache: yes
tasks:
- name: Install Nginx web server
ansible.builtin.apt:
name: nginx
state: present
```

Et exécutons le, nous devrions obtenir la sortie suivante:

<figure>
<img src="content/images/blog/2023/ansible/ansible-playbook/ansible-playbook-pre-tasks.jpg">
<figcaption>
<span class="figure__legend">Exécution d'une pre-tasks.</span>
</figcaption>
</figure>

Où l'on constate qu'effectivement la première tâche exécutée est notre mise à jour d'index de paquets (nous parlerons plus en détails de la tâche « Gathering facts » lorsque nous aborderons les **variables**)

Nous ne détaillerons pas la section `post_tasks` puisqu'elle fonctionne exactement de la même manière.

## Aller plus loin avec les sources

- https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html
- https://docs.ansible.com/ansible/2.9/modules/list_of_all_modules.html
- https://yaml.org/spec/1.2.2/#912-document-markers
- https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_privilege_escalation.html
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 11511ad

Please sign in to comment.