Pour un rendu optimal, activez JavaScript

[My Ansible Journey] Bases et premier Playbook

 ·  ☕ 11 min de lecture  ·  🩆 Jeremy

Seconde partie de la sĂ©rie d’article consacrĂ©e Ă  Ansible. L’objectif est toujours le mĂȘme, monter en puissance sur l’outil en s’appuyant sur des cas d’usages. De mĂȘme que pour la partie prĂ©requis, ce sera un mĂ©lange de bonnes pratiques provenant de l’Ă©diteur mais aussi de mon retour d’expĂ©rience.
Dans cet article, on revient sur les bases du produit ainsi que sur la rĂ©alisation d’un premier Playbook. On va commencer le dĂ©ploiement du Stack TIG (Telegraf, InfluxDB, Grafana) pour la supervision d’un environnement VMware (vCenter + ESXi), ce sera notre fil rouge :)

Pour rappel, les prĂ©requis c’est ici.

Le code des exemples qui suivent est sur GitHub

Introduction et objectifs d’Ansible

Il y avait dĂ©jĂ  eu une rapide introduction Ă  Ansible dans la premiĂšre partie, ici on va reparler de quelques cas d’usage avant de passer Ă  l’explication plus thĂ©orique.

A l’origine, le produit a Ă©tĂ© dĂ©veloppĂ© pour la gestion de la configuration de serveurs Linux. Il est sans agent, ce qui veut dire qu’il s’appuie sur SSH pour l’accĂšs aux nƓuds (serveurs qui seront gĂ©rĂ©s par Ansible). Une fois connectĂ© sur les nƓuds, c’est du code Python qui est exĂ©cutĂ©. De lĂ  dĂ©coule pour moi les points forts du produit :

  • Agentless grĂące Ă  SSH
  • Utilisation de SSH qui va permettre d’accĂ©der Ă©galement Ă  des Ă©quipements rĂ©seaux ou de sĂ©curitĂ© et ainsi Ă©largir le panel des nƓuds gĂ©rĂ©s.
  • ExĂ©cution de code Python (2 et 3), qui est prĂ©sent par dĂ©faut sur une majoritĂ© de systĂšme

On notera Ă©galement qu’il est possible de gĂ©rer des nƓuds Windows avec PowerShell mais Ă©galement n’importe quel Ă©quipement ou application que l’on peut accĂ©der via des web services (Rest API par exemple).
Si vous avez rĂ©alisĂ© les Ă©tapes listĂ©es dans les prĂ©requis, vous devez avoir un environnement Ansible prĂȘt pour Ă©crire vos Playbook. Comme vous l’avez vu, c’est plutĂŽt simple Ă  mettre en place, et vous n’avez besoin de rien d’autre pour les exĂ©cuter. A la maniĂšre de Python, on peut exĂ©cuter un Playbook de la maniĂšre suivante :

1
ansible-playbook playbook.yml

Cas d’usage

Un des cas d’usage le plus souvent citĂ© quand on parle d’Ansible, c’est le dĂ©ploiement et la configuration, sur un serveur Linux, d’un ensemble applicatif (par exemple serveur web + base de donnĂ©es). Du fait de l’idempotence native des modules, on peut rejouer le Playbook sur le serveur Linux, il n’y aura pas d’incidence, au contraire on corrigera une Ă©ventuelle dĂ©rive de configuration.

En vrac, quelques cas d’usages:

  • Automatiser le dĂ©ploiement d’équipements rĂ©seaux
  • DĂ©ploiement de machines virtuelles
  • Configuration de serveurs ESXi
  • En tant que PRA pour certaines applications : avoir un Playbook prĂȘt Ă  les redĂ©ployer.

Composants

  • Control Node : LĂ  oĂč on installe Ansible.
  • Managed Nodes : Equipements pilotĂ©s Ă  distance. Ils sont listĂ©s dans le fichier Inventory
  • Tower : Portail web de pilotage. AWX est l’Upstream de Tower.
  • Playbook : Description de la configuration souhaitĂ©e
  • Modules : Code qui est exĂ©cutĂ© sur les nƓuds

On reviendra sur les Playbook et Modules un peu plus loin dans l’article.

Fichiers nécessaires

On commence par voir les fichiers les plus importants, ceux qui sont suffisants pour faire un premier Playbook qui sera fonctionnel.

Playbook

Dans le Playbook on dĂ©crit la configuration que l’on souhaite retrouver appliquĂ©e sur les nƓuds. A la diffĂ©rence d’un script, ici il est plus question de description d’états que l’on souhaite obtenir, plutĂŽt que de tĂąches prĂ©cises Ă  exĂ©cuter.
Les Playbook sont Ă©crits en YAML, un langage proche du JSON. Explication sur la syntaxe ici : https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html

Inventaire

C’est dans le fichier d’inventaire que l’on dĂ©clare les nƓuds qui pourront ĂȘtre accĂ©dĂ©s avec le Playbook. Il en existe un par dĂ©faut : /etc/ansible/hosts.

Le fichier inventaire peut ĂȘtre sous deux formats :

  • Fichier .ini
  • Fichier .yml

Format .ini

Vous retrouverez plus souvent l’inventaire sous le format .ini, mais le second n’est pas Ă  ignorer car suivant l’inventaire souhaitĂ©, il peut apporter davantage de souplesse.

Dans notre exemple oĂč l’on va dĂ©ployer le stack TIG, voici Ă  quoi pourrait ressembler le fichier inventaire en .ini :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[tig]
influxdb ansible_host=192.168.1.10
telegraf ansible_host=192.168.1.11
grafana ansible_host=192.168.1.12

[webservers]
nginx01.domain.local
nginx02.domain.local

dns01.domain.local

Si on décompose le fichier :

  • [tig] est le nom du groupe et qui intĂ©gĂšre les 3 lignes suivantes. Le groupe peut-ĂȘtre utilisĂ© dans le Playbook.
  • influxdb est le nom que l’on souhaite donner au host. Il peut Ă©galement ĂȘtre utilisĂ© dans le Playbook.
  • ansible_host est une variable associĂ©e au host, chaque variable est sĂ©parĂ©e par un espace, puis on indique sa valeur prĂ©cĂ©dĂ© de =. Dans ce cas c’est l’ip du host.

J’ai ajoutĂ© un second groupe (qui ne servira pas dans notre exemple) pour montrer que l’on peut en crĂ©er autant que l’on souhaite. Il n’est pas indispensable de prĂ©ciser l’ip du host si on une rĂ©solution de nom fonctionnelle.

Et enfin pour finir, un host qui n’appartient Ă  aucun groupe.

Pour la dĂ©monstration, on va installer les 3 produits sur le mĂȘme serveur, donc on ne mettra qu’une seule ligne.

Format YAML

Voici l’Ă©quivalent en YAML :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
all:
  hosts:
  children:
    tig:
      hosts:
        influxdb:
            ansible_host: 192.168.1.10
        telegraf:
            ansible_host: 192.168.1.11
        grafana:
            ansible_host: 192.168.1.12
    webservers:
      hosts:
        nginx01.domain.local:
        nginx02.domain.local:
    dns01.domain.local:

Je pense que c’est suffisament clair pour comprendre la logique de ce format. A noter que les mots clĂ©s “all”, “hosts” et “children” sont rĂ©servĂ©s. Point important, “all” est implicitement prĂ©sent dans le fichier inventaire.ini, il correspond Ă  l’ensemble des hosts prĂ©sent dans l’inventaire.

Inventaire dynamique

Je ne vais pas rentrer dans les dĂ©tails sur les inventaires dynamiques dans cet article, car on n’en aura pas besoin tout de suite. Mais sachez que c’est trĂšs pratique qu’un inventaire puisse ĂȘtre gĂ©rĂ© depuis une source de donnĂ©es externe. Deux exemples :

  • Un serveur vCenter, permet d’avoir une liste VM Ă  jour dans l’inventaire
  • Un IPAM qui sert de Source of Truth, comme l’excellent NetBox

Je vous encourage Ă  vous rendre sur la documentation officielle pour approfondir la gestion des inventaires avec Ansible : https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html

Mode interactif

La fonction premiĂšre d’Ansible est bien d’exĂ©cuter des Playbook, mais Ă  des fins de test/debug, il est possible de l’utiliser en mode interactif. Par exemple si on souhaite savoir si un nƓud est accessible :

1
ansible grafana --inventoy inventory.ini --user jlg -m ping

Ici on se connecte Ă  l’hĂŽte grafana qui est dĂ©fini dans le fichier d’inventaire inventory.ini avec l’utilisateur jlg. Sur cet hĂŽte on exĂ©cute le module ping.

RĂ©sultat attendu :

1
2
3
4
5
6
7
grafana | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

On retrouve la documentation de chaque module via la commande :

1
ansible-doc ping

Ou directement sur le site d’Ansible : https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

On peut Ă©galement exĂ©cuter le module command qui est celui par dĂ©faut (on a donc pas besoin de le prĂ©ciser). Ce module attend un argument qui correspond Ă  la commande Ă  exĂ©cuter sur l’hĂŽte. Exemple :

1
ansible grafana --inventory inventory.ini --user jlg -a hostname

Comme indiquĂ©, on ne prĂ©cise pas le nom du module command car il est sĂ©lectionnĂ© par dĂ©faut, cependant on prĂ©cise l’argument avec -a, ici il va donc exĂ©cuter la commande hostname et nous renvoyer le rĂ©sultat :

1
2
grafana | CHANGED | rc=0 >>
tig

Enfin, la fonctionnalitĂ© la plus utile en mode interactif est la dĂ©couverte et l’affichage des Facts. Je reviendrai plus en dĂ©tail sur les Facts et variables avec Ansible dans le prochain article. Ce qu’il faut retenir ici, c’est la capacitĂ© qu’a Ansible Ă  dĂ©couvrir des informations sur le nƓud gĂ©rĂ© et Ă  les enregistrer dans des variables. Par exemple :

  • Informations Hardware, CPU, mĂ©moire, disques, rĂ©seau etc

  • Informations systĂšmes comme les adresses IP, nom et version de l’OS
  • Et plein d’autres choses

Le mieux étant encore de le tester, pour cela on exécute le module setup, sans argument :

1
ansible grafana --inventoy inventory.ini --user jlg -m setup

Le résultat est trÚs long, voici une partie :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
grafana | SUCCESS => {
    "ansible_facts": {
        "ansible_all_ipv4_addresses": [
            "192.168.x.x"
        ],
        "ansible_all_ipv6_addresses": [
            "fe80::20c:xxxx:xxxx:xxxx"
        ],
        "ansible_apparmor": {
            "status": "enabled"
        },
        "ansible_architecture": "x86_64",
        "ansible_bios_date": "02/27/2020",
        "ansible_bios_version": "6.00",
        "ansible_cmdline": {
            "BOOT_IMAGE": "/boot/vmlinuz-5.4.0-42-generic",
            "maybe-ubiquity": true,
            "ro": true,
            "root": "UUID=4ac4c187-b2ed-49ff-aa93-5b4ac3f13156b"
        },

On peut Ă©galement appliquer un filtre afin de limiter l’affichage, ici un exemple pour affichier les points de montage :

1
ansible grafana --inventory inventory.ini --user jlg -m setup -a 'filter=ansible_mounts'

Toutes ces informations vont pouvoir ĂȘtre rĂ©utilisĂ©es plus tard dans le Playbook, par exemple si vous souhaitez faire un contrĂŽle sur une version d’OS avant d’exĂ©cuter un tĂąche.

Composition d’un Playbook

On arrive maintenant au Playbook, on va rester simple ici aussi, le but Ă©tant d’introduire les concepts.

Voici le Playbook que l’on va exĂ©cuter :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
---
- name: Prerequisites
  hosts: tig
  gather_facts: yes
  remote_user: jlg
  become: true
  tasks:
    - name: Set timezone to Europe/Paris
      timezone:
        name: Europe/Paris
    
    - name: Local packages should be up-to-date
      apt:
        pkg: "*"
        state: latest

    - name: Add InfluxData Apt key
      apt_key:
        url: https://repos.influxdata.com/influxdb.key
        state: present

    - name: Add stable InfluxData Apt repository
      apt_repository:
        repo: "deb https://repos.influxdata.com/{{ ansible_facts['distribution']|lower }} {{ ansible_facts['distribution_release'] }} stable"
        state: present

- name: InfluxDB
  hosts: tig
  remote_user: jlg
  become: true
  gather_facts: false
  tasks:
    - name: Install InfluxDB
      apt:
        update_cache: yes
        pkg: influxdb

    - name: Service started and enabled
      service:
        name: influxdb
        enabled: yes
        state: started

MĂȘme si un Playbook a le mĂ©rite d’ĂȘtre comprĂ©hensible, il mĂ©rite quelques explications 😊

  1. Configuration de la Timezone
  2. Mise Ă  jour de tous les paquets
  3. Ajout du Repository apt d’InfluxData (Ă©diteur de de InfluxDB et Telegraf) avec la clĂ© associĂ©e
    • Ici on a exemple de l’utilisation des Facts vu plus haut avec la rĂ©cupĂ©ration de l’OS (ubuntu) et de la version (focal)
  4. Si InfluxDB n’est pas prĂ©sent, on l’installe.
    • Ici on prĂ©cise present et non pas latest, on veut que InfluxDB soit installĂ©, si c’est dĂ©jĂ  le cas, on ne souhaite pas le mettre Ă  jour.
  5. Enfn on dĂ©marre le service et on l’active (dĂ©marrage automatique)

Play

Un Playbook est divisé en plusieurs Play, ici on en retrouve deux, le premier commence dÚs le début avec :

1
- name: prerequisites

Le fait qu’il commence par un tiret indique que c’est une liste, et donc qu’il est proabable qu’il y en est plusieurs.

Un Play correspond Ă  une liste de tĂąches qui seront exĂ©cutĂ©es suivant les informations dans l’en-tĂȘte. Ces tĂąches seront exĂ©cuter dans l’odre, sur chacun des nƓuds. Cependant le traitement se fait en parallĂšle sur les nƓuds (si on a prĂ©cisĂ© un groupe au lieu d’un hĂŽte simple).

En-tĂȘte

Un en-tĂȘte par Play, la premiĂšre :

1
2
3
4
5
- name: Prerequisites
  hosts: tig
  gather_facts: yes
  remote_user: jlg
  become: yes

On retrouve des informations qu’on avait dĂ©jĂ  pu prĂ©ciser dans le mode interactif comme le host (ou groupe de hosts, on aurait pu mettre all ou grafana) et l’utilisateur distant. On y prĂ©cise quelques informations supplĂ©mentaires comme le fait qu’on rĂ©cupĂšre les Facts et que l’on souhaite obtenir une Ă©lĂ©vation de privilĂšge (become).

Task

C’est avec les Tasks qu’on indique quel est l’Ă©tat souhaitĂ© sur le nƓud. Si on regarde la premiĂšre Task :

1
2
3
    - name: Set timezone to Europe/Paris
      timezone:
        name: Europe/Paris

Le nom indiquĂ© est optionnel et servira notamment pour obtenir un affichage clair, mais aussi de marqueur si on souhaite relancer le Playbook depuis une tĂąche prĂ©cise. Ensuite vient l’appel du module timezone auquel on passe un argument correspondant Ă  la Timezone.

L’objectif de cette Task est donc d’avoir la Timezone prĂ©cisĂ©e de configurĂ©e sur le host. Si c’est le cas, il remontera un statut Ok, si il doit la modifier, il prĂ©cisera Changed. Dans cette logique, quand on relancera la Task, il remontera Ok et ne fera aucune modification.

Module

Enfin le module est le composant qui renferme le code Python qui sera exĂ©cutĂ© sur le nƓud, c’est lui qui doit ĂȘtre idempotent et donc s’assurer de ne faire des modifications que si nĂ©cessaire. Les modules sont accessibles directement sur Github : https://github.com/ansible/ansible/tree/stable-2.9/lib/ansible/modules

Exécution du Playbook

Enfin, on peut exécuter ce premier Playbook avec la commande suivante :

1
ansible-playbook playbook.yml --inventory inventory.ini -K

Cette fois on ne prĂ©cise pas d’utilisateur ni de nƓud sur lequel exĂ©cuter le Playbook, ces informations sont indiquĂ©es dans l’en-tĂȘte des Plays. On a cependant ajoutĂ© l’option -K afin que le prompt nous sollicite pour saisir le mot de passe permettant l’Ă©levation de privilĂšge (sudo par dĂ©faut).

Je vous encourage à le relancer plusieurs fois afin de voir la différence.

Cya!

Partagez