Resources attached to the Road To DevOps tutorial
https://blog.noobtoroot.xyz/road-to-devops/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
579 lines
15 KiB
579 lines
15 KiB
2 years ago
|
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
|
||
|
![Logo Ansible](images/logo-ansible.svg)
|
||
|
# Playbooks Ansible
|
||
|
|
||
|
Jouer et rejouer facilement un jeu de commandes prédéfini sur un ensemble de machines.
|
||
|
|
||
|
|
||
|
![Schéma archi globale](images/ansible-archi-playbooks.png)
|
||
|
|
||
|
|
||
|
## Format du Playbook
|
||
|
|
||
|
* Il se présente sous la forme d'un simple fichier texte au format `yaml`.
|
||
|
|
||
|
* Il peut donc être facilement versionné dans un outil de gestion de version.
|
||
|
|
||
|
|
||
|
### yaml
|
||
|
|
||
|
* Format ouvert de représentation de données.
|
||
|
|
||
|
* Acronyme récursif de _YAML Ain't Markup Language_.
|
||
|
|
||
|
* Permet de représenter des données complexes tout en conservant une excellente lisibilité.
|
||
|
|
||
|
* Utilisation en forte progression ces dernières années.
|
||
|
<small>Ansible, GitLab, Docker Compose, Kubernetes manifests, etc...</small>
|
||
|
|
||
|
* Site officiel : https://yaml.org/
|
||
|
|
||
|
|
||
|
### YAML basics
|
||
|
|
||
|
https://fr.wikipedia.org/wiki/YAML
|
||
|
|
||
|
* _attention_ ! l'indentation se fait avec un ou plusieurs espaces, jamais avec des tabulations !
|
||
|
|
||
|
* Les commentaires sont signalés par le signe dièse `#` et se prolongent sur toute la ligne.
|
||
|
|
||
|
* Les éléments de listes sont dénotés par le tiret `-`, suivi d'une espace, à raison d'un élément par ligne.
|
||
|
|
||
|
* Les tableaux sont de la forme `clé: valeur`, à raison d'un couple par ligne.
|
||
|
|
||
|
|
||
|
### YAML basics
|
||
|
|
||
|
https://fr.wikipedia.org/wiki/YAML
|
||
|
|
||
|
* Les chaînes de caractères peuvent être entourées de guillemets doubles `"`, ou simples `'`, sachant qu'un guillemet s'échappe avec un antislash `\`, alors qu'une apostrophe s'échappe avec une autre apostrophe.
|
||
|
|
||
|
* Les chaînes de caractères peuvent de plus être représentées par un bloc indenté avec des modificateurs facultatifs pour conserver `|` ou éliminer `>` les retours à la ligne.
|
||
|
|
||
|
* Plusieurs documents rassemblés dans un seul fichier sont séparés par trois traits d'union `---`.
|
||
|
|
||
|
|
||
|
### YAML basics
|
||
|
|
||
|
https://fr.wikipedia.org/wiki/YAML
|
||
|
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
```
|
||
|
---
|
||
|
receipt: Oz-Ware Purchase Invoice
|
||
|
date: 2012-08-06
|
||
|
customer:
|
||
|
given: Dorothy
|
||
|
family: Gale
|
||
|
|
||
|
items:
|
||
|
- part_no: A4786
|
||
|
descrip: Water Bucket (Filled)
|
||
|
price: 1.47
|
||
|
quantity: 4
|
||
|
|
||
|
- part_no: E1628
|
||
|
descrip: High Heeled "Ruby" Slippers
|
||
|
size: 8
|
||
|
price: 100.27
|
||
|
quantity: 1
|
||
|
|
||
|
bill-to: &id001
|
||
|
street: |
|
||
|
123 Tornado Alley
|
||
|
Suite 16
|
||
|
city: East Centerville
|
||
|
state: KS
|
||
|
|
||
|
ship-to: *id001
|
||
|
|
||
|
specialDelivery: >
|
||
|
Follow the Yellow Brick
|
||
|
Road to the Emerald City.
|
||
|
Pay no attention to the
|
||
|
man behind the curtain.
|
||
|
...
|
||
|
```
|
||
|
|
||
|
|
||
|
### yaml - Définition d’une collection (-)
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
|
||
|
```yaml
|
||
|
# Une liste de fruits
|
||
|
fruits:
|
||
|
- pomme
|
||
|
- orange
|
||
|
- framboise
|
||
|
- mangue
|
||
|
```
|
||
|
|
||
|
Forme abrégée :
|
||
|
```yaml
|
||
|
# Une liste de fruits
|
||
|
fruits: ['pomme', 'orange', 'framboise', 'mangue']
|
||
|
```
|
||
|
|
||
|
|
||
|
### Définition d’un dictionnaire (key: value)
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
|
||
|
```yaml
|
||
|
# Un utilisateur
|
||
|
martin:
|
||
|
name: Martin Dupond
|
||
|
job: developer
|
||
|
skill: python
|
||
|
```
|
||
|
|
||
|
Forme abrégée :
|
||
|
```yaml
|
||
|
# Un utilisateur
|
||
|
martin: { name: Martin Dupond, job: developer, skill: python }
|
||
|
```
|
||
|
|
||
|
|
||
|
## Tasks
|
||
|
|
||
|
* Les commandes d'un Playbook sont découpées en instructions unitaires appelées _tâches_ (tasks).
|
||
|
|
||
|
* Chaque tâche exécute un module Ansible avec des paramètres spécifiques.
|
||
|
|
||
|
* Format d'une tâche :
|
||
|
|
||
|
```none
|
||
|
- name: Description de la tâche
|
||
|
<nom-du-module>:
|
||
|
<paramètre-1>: <valeur-1>
|
||
|
<paramètre-2>: <valeur-2>
|
||
|
<paramètre-3>: <valeur-3>
|
||
|
```
|
||
|
|
||
|
|
||
|
### Liste de tâches
|
||
|
|
||
|
* Un playbook peut décrire une liste de plusieurs tâches.
|
||
|
|
||
|
* Les tâches seront exécutées dans l'ordre d'apparition et de façon séquentielle sur chacune des machines cibles.
|
||
|
|
||
|
```none
|
||
|
tasks: <----------------------------- liste de tâche
|
||
|
|
||
|
- name: Ma tâche 1 <--------------- tâche 1
|
||
|
<nom-du-module>:
|
||
|
<paramètre-1>: <valeur-1>
|
||
|
<paramètre-2>: <valeur-2>
|
||
|
<paramètre-3>: <valeur-3>
|
||
|
|
||
|
- name: Ma tâche 2 <--------------- tâche 2
|
||
|
<nom-du-module>:
|
||
|
<paramètre-1>: <valeur-1>
|
||
|
<paramètre-2>: <valeur-2>
|
||
|
```
|
||
|
|
||
|
|
||
|
### Exemple réel
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
```yaml
|
||
|
- hosts: web # exécution d'un 'Play' sur le groupe 'web'
|
||
|
tasks:
|
||
|
- name: Installation of Apache Package # tâche 1
|
||
|
yum:
|
||
|
name: httpd
|
||
|
state: present
|
||
|
update_cache: yes
|
||
|
|
||
|
- name: Ensure Apache is running (and enabled at boot) # tâche 2
|
||
|
service: name=httpd state=started enabled=yes
|
||
|
```
|
||
|
|
||
|
* Ici on mixe les deux types de syntaxes (normale et abrégée).
|
||
|
* __Les bonnes pratiques préconisent l'utilisation de la syntaxe normale.__
|
||
|
|
||
|
|
||
|
### Exemple réel
|
||
|
avec syntaxe normale
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
```yaml
|
||
|
- hosts: web
|
||
|
tasks:
|
||
|
- name: Installation of Apache Package
|
||
|
yum:
|
||
|
name: httpd
|
||
|
state: present
|
||
|
update_cache: yes
|
||
|
|
||
|
- name: Ensure Apache is running (and enabled at boot)
|
||
|
service:
|
||
|
name: httpd
|
||
|
state: started
|
||
|
enabled: yes
|
||
|
```
|
||
|
|
||
|
|
||
|
### Notion de Play
|
||
|
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
```yaml
|
||
|
---
|
||
|
- hosts: webservers # Play 1 sur le groupe webservers
|
||
|
tasks:
|
||
|
- name: My task
|
||
|
...
|
||
|
|
||
|
- hosts: databases # Play 2 sur le groupe databases
|
||
|
tasks:
|
||
|
- name: My task...
|
||
|
...
|
||
|
```
|
||
|
|
||
|
* Chaque Play contient sa propre liste de tâches et cible un ensemble spécifique de machines.
|
||
|
|
||
|
|
||
|
## Lancer un playbook
|
||
|
|
||
|
<small>`$ ansible-playbook <fichier-playbook> -i <fichier-inventaire>`</small>
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
$ ansible-playbook playbook.yaml -i ./hosts
|
||
|
|
||
|
PLAY [web] *******************************************************************
|
||
|
|
||
|
TASK [setup] *****************************************************************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
TASK [Installation du package Apache] ****************************************
|
||
|
changed: [web2.formation.sii.fr]
|
||
|
changed: [web1.formation.sii.fr]
|
||
|
|
||
|
TASK [Ensure Apache is running (and enable it at boot)] **********************
|
||
|
changed: [web1.formation.sii.fr]
|
||
|
changed: [web2.formation.sii.fr]
|
||
|
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
```
|
||
|
<small>
|
||
|
* Notre Playbook comportait 2 tâches seulement, nous en voyons 3 !
|
||
|
|
||
|
* Ansible a automatiquement ajouté à l'exécution une tâche nommée _setup_ dont l'objectif est de récupérer les _facts_ des machines cibles.
|
||
|
<small>
|
||
|
|
||
|
|
||
|
## Récapitulatif du Playbook
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
* Sur les 2 machines cibles :
|
||
|
|
||
|
- `ok` : 3 tâches ont été exécutées avec succès.
|
||
|
- `changed` : 2 tâches ont modifié l'état du système.
|
||
|
- `unreachable` : Toutes les machines étaient joignables.
|
||
|
- `failed` : Aucune tâche n'a échoué.
|
||
|
|
||
|
|
||
|
## Relancer un playbook
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
$ ansible-playbook playbook.yaml -i ./hosts --become
|
||
|
|
||
|
PLAY [web] *******************************************************************
|
||
|
|
||
|
TASK [setup] *****************************************************************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
TASK [Installation du package Apache] ****************************************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
TASK [Ensure Apache is running (and enable it at boot)] **********************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=0 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=0 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
|
||
|
## Première exécution
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
## Seconde exécution
|
||
|
|
||
|
```none
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=0 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=0 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
|
||
|
## Ordre d'exécution
|
||
|
|
||
|
* Il est possible de contrôler l'ordre dans lequel les machines cibles sont adressées.
|
||
|
|
||
|
* L'ordre par défaut est l'ordre d'apparition dans l'inventaire.
|
||
|
|
||
|
```yaml
|
||
|
- hosts: all
|
||
|
order: sorted # l'ordre est défini ici
|
||
|
gather_facts: False
|
||
|
tasks:
|
||
|
- debug:
|
||
|
var: inventory_hostname
|
||
|
```
|
||
|
|
||
|
|
||
|
Ordre | Description
|
||
|
- | -
|
||
|
`inventory` | Ordre d'apparition dans l'inventaire. C'est le choix par défaut.
|
||
|
`reverse_inventory` | Ordre inverse d'apparition dans l'inventaire.
|
||
|
`sorted` | Ordre alphabétique des noms de machines.
|
||
|
`reverse_sorted` | Ordre alphabétique inverse des noms de machines.
|
||
|
`shuffle` | Ordre aléatoire.
|
||
|
|
||
|
|
||
|
## Démarrer l'exécution à un endroit précis
|
||
|
|
||
|
`$ ansible-playbook playbook.yaml --start-at-task="my task"`
|
||
|
|
||
|
Cette commande démarre l'exécution du playbook à partir de la tâche nommée `my task`.
|
||
|
|
||
|
<small>https://docs.ansible.com/ansible/latest/user_guide/playbooks_startnstep.html</small>
|
||
|
|
||
|
|
||
|
## Ignorer le code de retour d'une commande
|
||
|
|
||
|
* Les modules _command_ et _shell_ sont sensibles au code de retour des commandes.
|
||
|
|
||
|
* Pour ignorer les erreurs sur une commande qui renvoie un code > 0 on peut utiliser `ignore_errors`.
|
||
|
|
||
|
* Ou, utiliser `failed_when`.
|
||
|
|
||
|
* De même, `changed_when` peut être utilisé.
|
||
|
|
||
|
```yaml
|
||
|
tasks:
|
||
|
- name: run this command and ignore the result
|
||
|
shell: /usr/bin/somecommand
|
||
|
ignore_errors: True
|
||
|
```
|
||
|
|
||
|
|
||
|
## Déclaration de variables
|
||
|
|
||
|
```yaml
|
||
|
- hosts: web
|
||
|
vars:
|
||
|
- app_directory: /var/www/html
|
||
|
- app_user: apache
|
||
|
- app_group: apache
|
||
|
|
||
|
tasks:
|
||
|
- name: Modify permission on {{ app_directory }}
|
||
|
file:
|
||
|
dest: '{{ app_directory }}'
|
||
|
mode: 0755
|
||
|
owner: '{{ app_user }}'
|
||
|
group: '{{ app_group }}'
|
||
|
recurse: yes
|
||
|
```
|
||
|
|
||
|
Les variables sont déclarées dans _vars_
|
||
|
et résolues avec `{{ }}`.
|
||
|
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
$ ansible-playbook playbook.yaml -i ./hosts
|
||
|
|
||
|
PLAY [web] ****************************************************************
|
||
|
|
||
|
TASK [setup] **************************************************************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
TASK [Modify permission of directory /var/www/html] ***********************
|
||
|
changed: [web1.formation.sii.fr]
|
||
|
changed: [web2.formation.sii.fr]
|
||
|
|
||
|
PLAY RECAP ****************************************************************
|
||
|
web1.formation.sii.fr : ok=2 changed=1 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=2 changed=1 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
|
||
|
## Les _handlers_ et les _notify_
|
||
|
|
||
|
<!-- .slide: data-state="medium-code" -->
|
||
|
```yaml
|
||
|
- hosts: web
|
||
|
vars:
|
||
|
- apache_listen_port: 8080
|
||
|
|
||
|
tasks:
|
||
|
- name: Modify Apache configuration
|
||
|
lineinfile:
|
||
|
dest: /etc/httpd/conf/httpd.conf
|
||
|
regexp: '^Listen '
|
||
|
line: 'Listen {{ apache_listen_port }}'
|
||
|
notify: Reload Apache # Signale que la configuration
|
||
|
# d'Apache doit être rechargée
|
||
|
handlers:
|
||
|
- name: Reload Apache # Recharge la configuration
|
||
|
service:
|
||
|
name: httpd
|
||
|
state: reloaded
|
||
|
```
|
||
|
|
||
|
|
||
|
<!-- .slide: data-state="small-code" -->
|
||
|
```none
|
||
|
$ ansible-playbook playbook.yaml -i ./hosts
|
||
|
|
||
|
PLAY [web] *******************************************************************
|
||
|
|
||
|
TASK [setup] *****************************************************************
|
||
|
ok: [web1.formation.sii.fr]
|
||
|
ok: [web2.formation.sii.fr]
|
||
|
|
||
|
TASK [Modify Apache configuration] *******************************************
|
||
|
changed: [web1.formation.sii.fr]
|
||
|
changed: [web2.formation.sii.fr]
|
||
|
|
||
|
RUNNING HANDLER [Reload Apache] *********************************************
|
||
|
changed: [web1.formation.sii.fr]
|
||
|
changed: [web2.formation.sii.fr]
|
||
|
|
||
|
PLAY RECAP *******************************************************************
|
||
|
web1.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
web2.formation.sii.fr : ok=3 changed=2 unreachable=0 failed=0
|
||
|
```
|
||
|
|
||
|
|
||
|
## Idempotence
|
||
|
|
||
|
* L'idempotence signifie qu'une opération a le même effet qu'on l'applique une ou plusieurs fois.
|
||
|
|
||
|
* Les commandes d'un Playbook doivent être écrites de manière à produire le même résultat quel que soit le nombre de fois où elles sont exécutées sur une même cible.
|
||
|
|
||
|
|
||
|
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
|
||
|
## Travaux pratiques
|
||
|
|
||
|
![Travaux pratiques](images/tp.gif)
|
||
|
|
||
|
<small>[TP Ansible : playbooks](travaux-pratiques/tp-ansible-playbooks.html)</small>
|
||
|
|
||
|
|
||
|
## Variables sur la ligne de commande
|
||
|
|
||
|
Il est possible d'initialiser des variables directement sur la ligne de commande avec l'option `--extra-vars` (ou `-e`).
|
||
|
|
||
|
|
||
|
* Ces variables peuvent être définies sous la forme :
|
||
|
|
||
|
- chaîne de caractères
|
||
|
|
||
|
`$ ansible-playbook playbook.yaml --extra-vars "my_var_1=foo my_var_2=bar"`
|
||
|
|
||
|
- json
|
||
|
|
||
|
`$ ansible-playbook playbook.yaml --extra-vars '{"my_var_1":"foo","my_var_2":"bar"}'`
|
||
|
|
||
|
`$ ansible-playbook playbook.yaml --extra-vars '{"my_var":"foo","my_list":["foo","bar"]}'`
|
||
|
|
||
|
|
||
|
* Utilisez le fomat _json_ si vous voulez passer autre chose que des _strings_ :
|
||
|
|
||
|
- booleans
|
||
|
- integers
|
||
|
- floats
|
||
|
- lists
|
||
|
- ...
|
||
|
|
||
|
|
||
|
## Découper un Playbook
|
||
|
|
||
|
* Un Playbook peut se présenter sous la forme d'un fichier unique.
|
||
|
|
||
|
* Toutefois il est possible de le découper en plusieurs fichiers séparés afin de mieux organiser et favoriser la ré-utilisation de certaines parties.
|
||
|
|
||
|
* Il existe plusieurs manières de découper un Playbook :
|
||
|
les _includes_, les _imports_, et les _roles_.
|
||
|
|
||
|
<small>https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse.html</small>
|
||
|
|
||
|
|
||
|
### Includes et Imports
|
||
|
|
||
|
* Disponibles à partir de Ansible v2.4.
|
||
|
|
||
|
* Permettent le découpage des tâches d'un gros Playbook en fichiers plus petits.
|
||
|
|
||
|
* Ces fichiers peuvent ensuite être appelés :
|
||
|
|
||
|
- depuis un ou plusieurs Playbooks
|
||
|
|
||
|
- plusieurs fois dans un même Playbook.
|
||
|
|
||
|
|
||
|
### Import dynamique vs statique
|
||
|
|
||
|
* Les commandes `import` permettent
|
||
|
un chargement statique.
|
||
|
<small>(import_playbook, import_tasks, etc.)</small>
|
||
|
|
||
|
* Les commandes `include` permettent
|
||
|
un chargement dynamique.
|
||
|
<small>(include_tasks, include_role, etc.)</small>
|
||
|
|
||
|
|
||
|
### Statique vs Dynamique
|
||
|
|
||
|
* _Statique_
|
||
|
Ansible traite les imports statique au moment de l'analyse du Playbook (avant l'exécution).
|
||
|
|
||
|
* _Dynamique_
|
||
|
Ansible traite les imports dynamiques au fur et à mesure durant l'exécution du Playbook.
|
||
|
|
||
|
* Les imports statiques et dynamiques peuvent être mixés, toutefois cela n'est pas recommandé car cela rend le debug des Playbooks plus complexe.
|
||
|
|
||
|
|
||
|
### Import de Playbooks
|
||
|
|
||
|
* Il est possible d'importer un ou plusieurs Playbooks à l'intérieur d'un Playbook maître, avec `import_playbook`.
|
||
|
|
||
|
|
||
|
### Roles
|
||
|
|
||
|
* Plus puissants que les _includes_ et les _imports_.
|
||
|
|
||
|
* Permettent d'empaqueter un ensemble de tâches ainsi que les variables, handlers et autres autres éléments associés.
|
||
|
|
||
|
* Les _roles_ peuvent être facilement ré-utilisés et partagés.
|
||
|
|
||
|
|
||
|
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
|
||
|
## Travaux pratiques
|
||
|
|
||
|
![Travaux pratiques](images/tp.gif)
|
||
|
|
||
|
<small>[TP Ansible : imports](travaux-pratiques/tp-ansible-imports.html)</small>
|