Browse Source

(Fix) Bad files path

master
Bertrand Janvoie 2 years ago
parent
commit
ed8b804c09
  1. 2
      Pepiniere/Pepinière/ansible/.gitignore
  2. 29
      Pepiniere/Pepinière/ansible/.gitlab-ci.yml
  3. 3
      Pepiniere/Pepinière/ansible/.gitmodules
  4. 118
      Pepiniere/Pepinière/ansible/0.Introduction-formation.md
  5. 206
      Pepiniere/Pepinière/ansible/1.Introduction-ansible.md
  6. 85
      Pepiniere/Pepinière/ansible/10.bonnes-pratiques.md
  7. 328
      Pepiniere/Pepinière/ansible/2.installation-inventaire.md
  8. 384
      Pepiniere/Pepinière/ansible/3.commandes-ad-hoc.md
  9. 578
      Pepiniere/Pepinière/ansible/4.playbooks.md
  10. 409
      Pepiniere/Pepinière/ansible/5.roles.md
  11. 385
      Pepiniere/Pepinière/ansible/6.structures-de-controle.md
  12. 516
      Pepiniere/Pepinière/ansible/7.templates.md
  13. 306
      Pepiniere/Pepinière/ansible/8.notions-avancees.md
  14. 246
      Pepiniere/Pepinière/ansible/9.Ansible-Galaxy.md
  15. 29
      Pepiniere/Pepinière/ansible/README.md
  16. 54
      Pepiniere/Pepinière/ansible/ansible-config-virtualbox-vms.md
  17. BIN
      Pepiniere/Pepinière/ansible/images/ansible-ad-hoc-deployment-workflow.png
  18. BIN
      Pepiniere/Pepinière/ansible/images/ansible-ad-hoc-multi-node-deployment.png
  19. BIN
      Pepiniere/Pepinière/ansible/images/ansible-archi-playbooks.png
  20. BIN
      Pepiniere/Pepinière/ansible/images/ansible-archi-roles.png
  21. BIN
      Pepiniere/Pepinière/ansible/images/ansible-archi-ssh.png
  22. BIN
      Pepiniere/Pepinière/ansible/images/ansible-galaxy-site.png
  23. BIN
      Pepiniere/Pepinière/ansible/images/ansible-playbook-deployment-workflow.png
  24. BIN
      Pepiniere/Pepinière/ansible/images/ansible-playbook-multi-node-deployment-workflow.png
  25. BIN
      Pepiniere/Pepinière/ansible/images/ci-vs-cd-devops-difference.jpg
  26. 70
      Pepiniere/Pepinière/ansible/images/logo-ansible.svg
  27. BIN
      Pepiniere/Pepinière/ansible/images/logo-molecule.png
  28. 240
      Pepiniere/Pepinière/ansible/images/logo-testinfra.svg
  29. BIN
      Pepiniere/Pepinière/ansible/images/manual-deployment-without-ansible.png
  30. BIN
      Pepiniere/Pepinière/ansible/images/tower-dashboard.png
  31. BIN
      Pepiniere/Pepinière/ansible/images/tp.gif
  32. 150
      Pepiniere/Pepinière/ansible/index.html
  33. 72
      Pepiniere/Pepinière/ansible/introduction.html
  34. 28
      Pepiniere/Pepinière/ansible/travaux-pratiques/2.tp-deploiement-app.md
  35. 5
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/apache-handlers.yaml
  36. 38
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/apache-install.yaml
  37. 19
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/mariadb-install.yaml
  38. 20
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/mariadb-wordpress-configure.yaml
  39. 31
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/wordpress-configure.yaml
  40. 18
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/wordpress-install.yaml
  41. 26
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/install-apache-wordpress-mariadb-imports.yaml
  42. 18
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/apache-wordpress-mariadb-roles-password.yaml
  43. 5
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/inventories/formation/group_vars/centos7.yaml
  44. 17
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/inventories/formation/hosts
  45. 1
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/passwords.txt
  46. 33
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/apache-install/tasks/main.yaml
  47. 19
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/mariadb-configure/tasks/main.yml
  48. 18
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/mariadb-install/tasks/main.yaml
  49. 30
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/wordpress-configure/tasks/main.yml
  50. 16
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/wordpress-install/tasks/main.yml
  51. 6
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/inventories/formation/group_vars/wordpress.yaml
  52. 10
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/inventories/formation/hosts
  53. 9
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/playbook.yaml
  54. 36
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/apache/tasks/main.yaml
  55. 4
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/defaults/main.yml
  56. 19
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/add-database.yml
  57. 18
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/install.yaml
  58. 2
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/main.yaml
  59. 3
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/meta/main.yml
  60. 30
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/configure.yml
  61. 16
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/install.yml
  62. 2
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/main.yaml
  63. 6
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/hosts
  64. 149
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/install-apache-wordpress-mariadb.yaml
  65. 53
      Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/script-tp2.sh
  66. BIN
      Pepiniere/Pepinière/ansible/travaux-pratiques/images/ansible-archi-ssh.png
  67. BIN
      Pepiniere/Pepinière/ansible/travaux-pratiques/images/ansible-galaxy-search-role.png
  68. 1
      Pepiniere/Pepinière/ansible/travaux-pratiques/revealjs
  69. 72
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-divers.html
  70. 15
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-divers.md
  71. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-galaxy.html
  72. 111
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-galaxy.md
  73. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-imports.html
  74. 215
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-imports.md
  75. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-inventaire.html
  76. 268
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-inventaire.md
  77. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-les-commandes-ad-hoc.html
  78. 287
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-les-commandes-ad-hoc.md
  79. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-playbooks.html
  80. 434
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-playbooks.md
  81. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-roles.html
  82. 345
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-roles.md
  83. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-structures-de-controle.html
  84. 55
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-structures-de-controle.md
  85. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-templates.html
  86. 36
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-templates.md
  87. 96
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-vault.html
  88. 283
      Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-vault.md
  89. 29
      Pepiniere/Pepinière/devops/.gitlab-ci.yml
  90. 3
      Pepiniere/Pepinière/devops/.gitmodules
  91. 52
      Pepiniere/Pepinière/devops/0.introduction.md
  92. 163
      Pepiniere/Pepinière/devops/1.constats.md
  93. 156
      Pepiniere/Pepinière/devops/2.apport.md
  94. 83
      Pepiniere/Pepinière/devops/3.origines.md
  95. 66
      Pepiniere/Pepinière/devops/4.pratique.md
  96. 101
      Pepiniere/Pepinière/devops/5.integration.md
  97. 80
      Pepiniere/Pepinière/devops/6.conclusion.md
  98. 8
      Pepiniere/Pepinière/devops/Dockerfile
  99. 10
      Pepiniere/Pepinière/devops/README.md
  100. 221
      Pepiniere/Pepinière/devops/images/Devops-toolchain.svg
  101. Some files were not shown because too many files have changed in this diff Show More

2
Pepiniere/Pepinière/ansible/.gitignore vendored

@ -0,0 +1,2 @@
*.pdf
*.zip

29
Pepiniere/Pepinière/ansible/.gitlab-ci.yml

@ -0,0 +1,29 @@
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build
make-pdf:
stage: build
image:
name: astefanutti/decktape:2.11.0
entrypoint: [""]
tags:
- france
- sii
script:
#
# 1. We change the size with --size due to a strange rendering bug
# decribed here: https://github.com/astefanutti/decktape/issues/151
#
# 2. We also specify --chrome-arg=--disable-web-security to autorize
# Cross origin requests in chrome
#
- node /decktape/decktape.js --chrome-path chromium-browser --chrome-arg=--no-sandbox --chrome-arg=--disable-web-security --size='1576x1182' index.html ansible-formation.pdf
artifacts:
name: ansible.pdf
expire_in: 3 month
paths:
- ansible-formation.pdf

3
Pepiniere/Pepinière/ansible/.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "revealjs"]
path = revealjs
url = ../../template-revealjs-sii-theme.git

118
Pepiniere/Pepinière/ansible/0.Introduction-formation.md

@ -0,0 +1,118 @@
# Ansible
__Formation__
Christian Tritten • Stéfan Lebosq
## Pré-requis
* Virtualbox
4 VMs téléchargées et importées
* Putty
https://www.putty.org/
* Café (!)
## Formation à distance
* Laisser votre caméra allumée afin de favoriser
les échanges
* Vous pouvez intervenir quand vous voulez...
mais gardez votre micro coupé le reste du temps
* Levez la main en cas de problème
(debug sur les TPs en aparté)
* Double pause pour éviter la surchauffe !
## Horaires jour
|||
|:-|-:|
|démarrage|__9h30__|
|pause|__~ 10h30 ~ 11h30__|
|repas|__12h30__|
|reprise|__14h00__|
|pause|__~ 15h00 ~ 16h00__|
|fin|__17h30__|
## Badge
Le port du badge SII de façon visible
est obligatoire dans les locaux.
## Tour de table
* Qui êtes-vous ?
* Connaissez-vous déjà Ansible ou des outils similaires ?
* Qu'attendez-vous de la formation ?
* Avez-vous des à priori sur le mode distanciel ?
## Programme
### 1. Introduction
* DevOps et Infrastructure as Code
* Présentation d'Ansible
### 2. Installation et Mise en œuvre
* Installation et configuration
* Configuration SSH
* Mise en place de l’inventaire
### 3. Les commandes Ad-Hoc
* CLI Ansible
* Principaux modules Ad-Hoc
### 4. Les Playbooks
* Définition de tâches
* Utilisation de variables
* Handlers et Notify
* Notion de rôles
### 5. Les structures de contrôle
* Les facts
* Les boucles et conditions
* Les inclusions
### 6. Les Templates
* Jinja2
* Filtres
* Tests
### 7. Notions avancées
* Ansible Vault
* Tester ses Playbooks Ansible
* Développer ses propres modules
## C'est parti !!!
[La formation](index.html)
## Ressources internes
<!-- .slide: data-state="cheat-sheet" -->
1. Formation Ansible SII
<small>[https://gitlab.siinergy.net/sii-ouest/trainings/ansible](https://gitlab.siinergy.net/sii-ouest/trainings/ansible)</small>
2. Mattermost DevOps SII ouest
<small>[https://mattermost.siinergy.net/ouest/channels/topic-devops](https://mattermost.siinergy.net/ouest/channels/topic-devops)</small>

206
Pepiniere/Pepinière/ansible/1.Introduction-ansible.md

@ -0,0 +1,206 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
# Ansible
![Logo Ansible](images/logo-ansible.svg)
<small>Antoire Bouhier • Christian Tritten • Alban Berthout</small>
## DevOps
## Infrastructure as Code
## DevOps
* Mouvement qui consiste à promouvoir le dialogue et la collaboration entre les équipes _Dev_ et _Ops_.
* Ensemble de bonnes pratiques et de principes
établis entre :
- les équipes DEV (de développement)
- les équipes OPS (d’exploitations)
* L'objectif de DevOps est de _fluidifier le processus de déploiement_ d'une application.
## Les principaux axes du DevOps
1. Améliorer la communication
<small>Organisation • Collaboration • Partage d'outils communs • Conférences • Réunions</small>
2. Accepter et banaliser les erreurs
<small>Droit à l'erreur • Responsabilité partagée</small>
3. Mettre en prod le plus souvent possible
<small>Robustesse • Confiance</small>
4. Automatiser tout ce qui peut l'être
<small>Tests • Cloud • Déploiements • Configuration • Chaos monkey</small>
5. Récolter des métriques et indicateurs
dans une optique d'amélioration continue
## Le champ d'application du DevOps
![devops](images/ci-vs-cd-devops-difference.jpg)
## Automatisation
Traiter de manière automatique les opérations
* de contrôle,
* de régulation,
* d’administration,
avec peu ou pas d’intervention humaine.
## Intérêt de l'automatisation
* Réduire la complexité
* Réduire les possibilités d’erreurs humaine
* Améliorer les performance d’un système
* Augmenter la productivité et l’innovation
* Améliorer la robustesse, l’agilité du déploiement
* Réduire le TTM d’une application
## Infrastructure As Code
* L'infrastructure cible peut-être décrite dans des fichiers de description à l'aide d'une syntaxe spécifique.
* Il devient alors possible de gérer et de versionner chaque modification apportée à l'infrastructure.
* Construire, reconstruire, modifier ou dupliquer une infrastructure s'en trouve d'autant simplifié.
* Outils : Terraform, Ansible, Puppet, Docker, Kubernetes...
## Les outils de gestion de configuration
* Permettent de contrôler l'ensemble des modifications apportées sur l’infrastructure d’une entreprise.
* Assurent que cette infrastructure est configurée selon les bonnes spécifications.
* Évitent l'apparition de trop grandes variations de configuration entre les serveurs.
## Quelques outils
- CFEngine (1993)
- Puppet (2005)
- Chef (2009)
- Ansible (2012)
## Ansible
* Logiciel libre (GPL-3.0)
* Initié en 2012
- Version 1.0 = 2013
- Version actuelle = 2.10 (2020), 2.9 pour Red Hat subscribers
* Développé en Python
[https://github.com/ansible/ansible](https://github.com/ansible/ansible)
* Forte communauté d'utilisateurs
* Ansible racheté par Red Hat en octobre 2015
* Red Hat racheté par IBM en octobre 2018
* Ansible est un moteur d'automatisation permettant :
- le provisionnement de logiciel,
- la gestion de la configuration.
* Pas d'agent
- utilise _SSH_ sur __Linux/Unix__
- utilise _WinRM_ sur __Windows__
* Mode _Push_
<small>Peut aussi fonctionner en _Pull_ (sur cibles Linux uniquement)</small>
### Cibles Linux
* La plupart des systèmes Linux sont supportés.
* Connexion par SSH.
* Pré-requis sur les machines cibles :
- SSH server
- Python 2.7 ou 3.5
### Cibles Windows
* Desktop :
Windows 7, 8.1, 10
* Server :
Windows Server 2008, 2008 R2, 2012, 2012 R2, 2016, 2019
* Connexion par WinRM.
* Pré-requis sur les machines cibles :
- PowerShell 3.0 ou +
- .NET 4.0 ou +
- Un WinRM listener doit être créé et activé.
### Documentation pour Windows
<small>https://docs.ansible.com/ansible/latest/user_guide/windows.html</small>
### Liste des modules pour Windows
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_windows_modules.html</small>
<small>https://docs.ansible.com/ansible/latest/collections/ansible/windows/index.html</small>
### Pourquoi utiliser Ansible ?
* Maîtrise des actions exécutées sur les machines cibles.
* Moins d'erreurs qu'avec des actions manuelles.
* Simple à mettre en oeuvre.
* Courbe d'apprentissage rapide.
* Syntaxe déclarative (pas de scripting).
* Libère les Ops des tâches répétitives.
### Sans outil de gestion de Configuration
![Schéma connexion sans Ansible](images/manual-deployment-without-ansible.png)
### Avec Ansible
![Schéma connexion avec Ansible](images/ansible-ad-hoc-deployment-workflow.png)

85
Pepiniere/Pepinière/ansible/10.bonnes-pratiques.md

@ -0,0 +1,85 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Bonnes pratiques
## Rester simple !
## Rester clair !
- Apporter tout le soin nécessaire à la lisibilité du code Ansible.
- Nommer toujours vos Plays et Tasks de manière précise et significative.
- Privilégiez la syntaxe YAML native.
<small>(Pas de : `name=httpd state=started enabled=yes`)</small>
- Ainsi fait, le code Ansible peut devenir la documentation de référence de votre workflow.
## Penser "déclaratif"
- Ansible permet de décrire un _état désiré_.
- Si vous essayez d'écrire du code dans vos playbooks et rôles, vous augmentez le risque d'échec.
- Utilisez prioritairement les Modules Ansible chaque fois que c'est possible.
## Utiliser les Roles
- Utilisez les Roles !
- Ils permettent un très bon découpage du code Ansible.
- Ils permettent de gérer des variables par défaut pour les composants.
## Attention aux variables !
- Ansible permet de déclarer des variables dans une grande variété d'emplacements. Il devient facile de s'y perdre !
- Évitez de trop disperser les déclarations de variables dans le code Ansible.
- Limitez les déclarations de variables à deux ou trois emplacements clés :
1. variables de groupes
2. variables de rôles
- Documenter précisément les variables que vous déclarez dans votre code Ansible.
## Eviter autant que possible les Modules "Commands"
- Les modules de commandes génériques tels que `shell` ou `command` peuvent conduire à certains dysfonctionnements. En effet les commandes Shell :
- ne sont pas toujours idempotentes.
- s'exécuteront toujours et retourneront l'état `changed` (à moins de spécifier `changed_when`).
- Les modules plus spécifiques sont souvent prévus pour être agnostique du système d'exploitation, ce qui permet d'augmenter la ré-utilisabilité du code.
## Eviter le module "lineinfile"
- Utiliser les modules `copy` ou `template` plutôt que `lineinfile` ou `replace`
- Pas besoin de connaître la syntaxe `regex`.
- Permet de contrôler exactement le contenu du fichier final.
## Créer des fichiers d’inventaires séparés
- Si vous devez gérer plusieurs environnements, créez des fichiers d'inventaires séparés afin d'éviter les problèmes !
## Les bonnes pratiques selon Ansible
<small>https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html</small>
## Autres bonnes pratiques
<small>https://www.serverraumgeschichten.de/2018/04/ansible-best-practices/</small>

328
Pepiniere/Pepinière/ansible/2.installation-inventaire.md

@ -0,0 +1,328 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Installation
## Installation d'Ansible
Environnement : CentOS 7 / 1vCPU / 512m RAM / 10G Disk
```none
$ sudo yum -y install epel-release
$ sudo yum -y update
$ sudo yum -y install ansible
$ ansible --version
ansible 2.9.16
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /bin/ansible
python version = 2.7.5 (default, Nov 16 2020, 22:23:17) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
```
Environnement : CentOS 8 / 1vCPU / 768m RAM / 10G Disk
```none
$ sudo dnf -y install epel-release
$ sudo dnf -y update
$ sudo dnf -y install ansible
$ ansible --version
ansible 2.9.16
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/ansible/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3.6/site-packages/ansible
executable location = /usr/bin/ansible
python version = 3.6.8 (default, Aug 24 2020, 17:57:11) [GCC 8.3.1 20191121 (Red Hat 8.3.1-5)]
```
## Configuration SSH
![Schéma connexion ssh](images/ansible-archi-ssh.png) <!-- .element: height="550px" -->
<!-- .slide: data-state="small-code" -->
1. Génération d'une paire de clés SSH
```none
ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (~/.ssh/id_rsa):
Created directory '/home/formation/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in ~/.ssh/id_rsa.
Your public key has been saved in ~/.ssh/id_rsa.pub.
The key fingerprint is:
08:d5:a7:66:ca:a0:0c:6c:2f:40:2b:0f:25:de:cf:4c root@centos7
The key's randomart image is:
+--[ RSA 2048]----+
| .o o.. |
| o +Eo |
| + . |
| . + o |
| S o = * o|
| . o @.|
| . = o|
| . o |
| o. |
+-----------------+
```
2. Copie de la clé publique sur les machines cibles
```none
ssh-copy-id -i formation@10.6.214.70
ssh-copy-id -i formation@10.6.214.72
ssh-copy-id -i formation@10.6.214.73
ssh-copy-id -i formation@10.6.214.74
```
## Configuration
<!-- .slide: data-state="small-table" -->
Fichier | Description
- | -
`/etc/ansible/ansible.cfg` | Fichier de configuration global
`~/.ansible.cfg` | Fichier de surcharge par utilisateur
`/path/to/project/ansible.cfg` | Fichier de surcharge par projet
`/path/to/project/ansible.cfg`
```toml
[defaults]
log_path=./ansible.log
roles_path = ./roles:/opt/othersite/roles
retry_files_save_path=./retries/
```
Exemple de surcharge locale de la configuration d'Ansible.
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Inventaire
Fichier de déclaration des machines cibles à adresser.
## Objectifs de l'inventaire
1. Déclarer la liste des machines à adresser.
2. Déclarer et associer des variables à :
- une machine en particulier,
- un sous-ensemble des machines,
- l'ensemble des machines.
![Inventaire](images/ansible-ad-hoc-multi-node-deployment.png)
* L'inventaire par défaut est défini dans le fichier `/etc/ansible/hosts`.
* Il faut être _root_ pour pouvoir le modifier.
* Il est également possible de créer un fichier inventaire à l'emplacement de notre choix.
* Il est aussi possible de gérer plusieurs inventaires correspondant à des plateformes différentes.
<small>Dans le homedir de l'utilisateur Ansible par exemple :</small>
<!-- .slide: data-state="medium-code" -->
```none
~/inventories/
├── dev
   └── hosts <----- inventaire de l'environnement de dev
├── qualif
   └── hosts <----- inventaire de l'environnement de qualif
└── prod
└── hosts <----- inventaire de l'environnement de production
```
## Déclaration de machines
Adresse IP
```none
10.6.214.70
10.6.214.72
10.6.214.73
10.6.214.74
```
Alias de la machine et adresse IP
```none
lb.formation.sii.fr ansible_host=10.6.214.70
web1.formation.sii.fr ansible_host=10.6.214.72
web2.formation.sii.fr ansible_host=10.6.214.73
bdd.formation.sii.fr ansible_host=10.6.214.74
```
<small>[https://docs.ansible.com/ansible/intro_inventory.html#hosts-and-groups](https://docs.ansible.com/ansible/intro_inventory.html#hosts-and-groups)</small>
Variables possibles pour les connexions :
* `ansible_host`
Le nom (si ce nom est différent de l'alias) ou l'adresse IP de la machine cible.
* `ansible_port`
Le port ssh (si différent de 22).
* `ansible_user`
L'utilisateur ssh à utiliser (si différent de l'utilisateur courant).
* `ansible_ssh_pass`
Le mot de passe ssh de l'utilisateur `ansible_user`.
* `ansible_ssh_private_key_file`
La clé privée utilisée par ssh. Utile en cas d'utilisation de plusieurs clés et si on ne veut pas utiliser SSH agent.
## Déclaration de groupes de machines
<!-- .slide: data-state="small-code" -->
```toml
lb.formation.sii.fr ansible_host=10.6.214.70
web1.formation.sii.fr ansible_host=10.6.214.72
web2.formation.sii.fr ansible_host=10.6.214.73
bdd.formation.sii.fr ansible_host=10.6.214.74
[lb] # groupe
lb.formation.sii.fr
[web]
web[1:2].formation.sii.fr # exemple de raccourci
# d'écriture
[db]
bdd.formation.sii.fr
[formation:children] # groupe de groupes
lb
web
db
```
## Groupes par défaut
* `all` : contient toutes les machines.
* `ungrouped` : contient toutes les machines qui n'appartiennent pas à un groupe (en dehors de `all`)
## Lancer une commande sur un groupe de machines spécifique
<!-- .slide: data-state="small-code" -->
```none
$ ansible formation -m ping
```
```json
10.6.214.70 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.6.214.74 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.6.214.72 | SUCCESS => {
"changed": false,
"ping": "pong"
}
10.6.214.73 | SUCCESS => {
"changed": false,
"ping": "pong"
}
```
## Variables de groupes
<!-- .slide: data-state="small-code" -->
```ini
...
[web]
web[1-2].formation.sii.fr
[db]
bdd.formation.sii.fr
[formation:children]
web
db
[formation:vars] # variables du groupe formation
ansible_user: "formation"
ansible_ssh_private_key_file: /home/formation/.ssh/id_rsa
```
## Vérifier les variables de l'inventaire
<!-- .slide: data-state="medium-code" -->
```none
$ ansible-inventory -i inventories/formation/hosts --list --yaml
```
```yaml
all:
children:
web:
hosts:
web1.formation.sii.fr:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.102
ansible_ssh_private_key_file: /home/ansible/.ssh/id_rsa
ansible_user: ansible
web2.formation.sii.fr:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.103
ansible_ssh_private_key_file: /home/ansible/.ssh/id_rsa
ansible_user: ansible
db:
hosts:
bdd.formation.sii.fr:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.104
ansible_ssh_private_key_file: /home/ansible/.ssh/id_rsa
ansible_user: ansible
```
## Externaliser les variables
A utiliser pour séparer les variables de la liste des machines.
<!-- .slide: data-state="small-code" -->
```none
~/inventories/
└── lab
   ├── group_vars
      ├── web <--- variables pour le groupe web
     └── db <--- variables pour le groupe db
├── host_vars
   ├── web1.formation.sii.fr <--- variables pour la machine web1
│ └── web2.formation.sii.fr <--- variables pour la machine web2
   └── hosts
```
Les dossiers `group_vars` et `host_vars` permettent l'organisation des fichiers de variables.
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
## Travaux pratiques
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible : Inventaire](travaux-pratiques/tp-ansible-inventaire.html)</small>

384
Pepiniere/Pepinière/ansible/3.commandes-ad-hoc.md

@ -0,0 +1,384 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Commandes Ad-Hoc
Exécuter des actions simples
sur un ensemble de machines.
## Les commandes Ad-Hoc ?
* Commandes permettant l'exécution simple, rapide et ponctuelle de commandes unitaires.
* Elles peuvent cibler
- une seule machine,
- un groupe de machines spécifique,
- l'ensemble des machines présentes dans l'inventaire.
* Elles se reposent sur les Modules Ansible.
## Les Modules Ansible
* Unités de traitement réutilisables.
* Permettent la réalisation d’une tâche précise.
* Écrits en Python.
* Code éprouvé.
* Nombreux modules disponibles.
* Possibilité d'écrire ses propres modules.
## Des centaines de modules disponibles !
<small>
Cloud Modules • Clustering Modules • Commands Modules • Crypto Modules •
Database Modules • Files Modules • Identity Modules • Inventory Modules •
Messaging Modules • Monitoring Modules • Network Modules • Notification
Modules • Packaging Modules • Source Control Modules • Storage Modules •
System Modules • Utilities Modules • Web Infrastructure Modules • Windows
Modules • ...
</small>
<small>https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html</small>
<small>https://docs.ansible.com/ansible/latest/collections/index.html</small>
## Utilisation de modules
`$ ansible <pattern> -m <module> [-a <params>]`
* `<pattern>` peut représenter :
- une machine
- toutes les machines (alias `all`)
- un groupe
- une expression
<!-- .slide: data-state="small-code" -->
```none
$ ansible formation:\!web -m command -a "uname -r"
bdd.formation.sii.fr | SUCCESS | rc=0 >>
3.10.0-327.28.3.el7.x86_64
lb.formation.sii.fr | SUCCESS | rc=0 >>
3.10.0-327.28.3.el7.x86_64
```
## Module Command
* À utiliser :
* pour des commandes simples
* Pour recueillir des informations
* Exemples :
* Éteindre/redémarrer des serveurs
* Copier des fichiers
* Créer des users/groups
* Installer des packages
### Exemple
<!-- .slide: data-state="medium-code" -->
Création rapide d'un utilisateur
sur un ensemble de machines
```none
$ ansible -m command -a "sudo useradd donald" 'formation'
10.6.214.70 | SUCCESS | rc=0 >>
10.6.214.73 | SUCCESS | rc=0 >>
10.6.214.74 | SUCCESS | rc=0 >>
10.6.214.72 | SUCCESS | rc=0 >>
$ ansible -m command -a "useradd donald" 'formation' --become
```
`--become` permet de passer changer d'utilisateur
pour jouer la commande.
### Exemple
<!-- .slide: data-state="medium-code" -->
Affichage des utilisateurs créés
```none
$ ansible -m command -a "grep donald /etc/passwd" 'formation'
10.6.214.74 | SUCCESS | rc=0 >>
donald:x:1009:1010::/home/donald:/bin/bash
10.6.214.70 | SUCCESS | rc=0 >>
donald:x:1009:1010::/home/donald:/bin/bash
10.6.214.72 | SUCCESS | rc=0 >>
donald:x:1009:1010::/home/donald:/bin/bash
10.6.214.73 | SUCCESS | rc=0 >>
donald:x:1009:1010::/home/donald:/bin/bash
```
## Documentation des modules
* Recherche "ansible module nom-module" (Google)
* `$ ansible-doc <nom-module>` (CLI)
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
## Travaux pratiques
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible : commandes ad-hoc bases](travaux-pratiques/tp-ansible-les-commandes-ad-hoc.html)</small>
## Modules de commandes
<!-- .slide: data-state="small-table" -->
Module (2.9) | Module (2.10) | Description
- | - | -
`command` | `ansible.builtin.command` | Executes a command on a remote node
`expect` | `ansible.builtin.expect` | Executes a command and responds to prompts.
`psexec` | `community.windows.psexec` | Runs commands on a remote Windows host based on the PsExec model
`raw` | `ansible.builtin.raw` | Executes a low-down and dirty SSH command
`script` | `ansible.builtin.script` | Runs a local script on a remote node after transferring it
`shell` | `ansible.builtin.shell` | Execute commands in nodes.
`telnet` | `ansible.netcommon.telnet` | Executes a low-down and dirty telnet command
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_commands_modules.html</small>
## Modules de gestion de fichiers
<!-- .slide: data-state="small-table" -->
Module (2.9) | Module (2.10) | Description
- | - | -
`blockinfile` | `ansible.builtin.blockinfile` | Insert/update/remove a text block surrounded by marker lines
`copy` | `ansible.builtin.copy` | Copies files to remote locations
`fetch` | `ansible.builtin.fetch` | Fetches a file from remote nodes
`file` | `ansible.builtin.file` | Sets attributes of files
`lineinfile` | `ansible.builtin.lineinfile` | Manage lines in text files
`replace` | `ansible.builtin.replace` | Replace all instances of a particular string in a file using a back-referenced regular expression.
`stat` | `ansible.builtin.stat` | Retrieve file or file system status
`template` | `ansible.builtin.template` | Templates a file out to a remote server
... | ... | ...
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_files_modules.html</small>
### Exemple
Modifier les attributs d'un fichier sur les machines
du groupe formation
<!-- .slide: data-state="small-code" -->
```none
$ ansible -m file -a "dest=/etc/foo mode=0660 owner=root group=root" \
formation
10.6.214.72 | SUCCESS => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0660",
"owner": "root",
"path": "/etc/foo",
"secontext": "system_u:object_r:net_conf_t:s0",
"size": 158,
"state": "file",
"uid": 0
...
}
```
## Modules de gestion de paquets
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_packaging_modules.html</small>
### Paquets Debian / Ubuntu
<!-- .slide: data-state="small-table" -->
Module (2.9) | Module (2.10) | Description
- | - | -
`apt` | `ansible.builtin.apt` | Manages apt-packages
`apt_key` | `ansible.builtin.apt_key` | Add or remove an apt key
`apt_repository` | `ansible.builtin.apt_repository` | Add and remove APT repositories
`dpkg_selections` | `ansible.builtin.dpkg_selections` | Dpkg package selection selections
`package` | `ansible.builtin.package` | Generic OS package manager
`package_facts` | `ansible.builtin.package_facts` | Package information as facts
<!-- .slide: data-state="small-table" -->
### Paquets RedHat / CentOS / Fedora
Module (2.9) | Module (2.10) | Description
- | - | -
`dnf` | `ansible.builtin.dnf` | Manages packages with the dnf package manager
`yum` | `ansible.builtin.yum` | Manages packages with the yum package manager
`yum_repository` | `ansible.builtin.yum_repository` |Add or remove YUM repositories
`redhat_subscription` | `community.general.redhat_subscription` | Manage registration and subscriptions to RHSM using subscription-manager
`rhn_channel` | `community.general.rhn_channel` | Adds or removes Red Hat software channels
`rhn_register` | `community.general.rhn_register` | Manage RHN registration using rhnreg_ks
`rhsm_repository` | `community.general.rhsm_repository` | Manage RHSM repositories using subscription-manager
`rpm_key` | `ansible.builtin.rpm_key` | Adds or removes a gpg key from the rpm db
`package` | `ansible.builtin.package` | Generic OS package manager
`package_facts` | `ansible.builtin.package_facts` | Package information as facts
<!-- .slide: data-state="small-table" -->
### Paquets Suse / OpenSuse
Module (2.9) | Module (2.10) | Description
- | - | -
`zypper` | `community.general.zypper` | Manage packages on SUSE and openSUSE
`zypper_repository` |`community.general.zypper_repository` | Add and remove Zypper repositories
`package` | `ansible.builtin.package` | Generic OS package manager
`package_facts` | `ansible.builtin.package_facts` | Package information as facts
<!-- .slide: data-state="small-table" -->
### Paquets relatifs à des langages de programmation
Module (2.9) | Module (2.10) | Description
- | - | -
`cpanm` | `community.general.cpanm` | Manages Perl library dependencies.
`gem` | `community.general.gem` | Manage Ruby gems
`npm` | `community.general.npm` | Manage node.js packages with npm
`pip` |`ansible.builtin.pip` | Manages Python library dependencies
... | ... | ...
### Exemple
Vérification de la présence d'un paquet
<!-- .slide: data-state="small-code" -->
```none
$ ansible -m yum -a "name=vim state=present" 'formation'
10.6.214.70 | SUCCESS => {
"changed": true,
"rc": 0,
"results": [
...
Installing :
2:vim-filesystem-7.4.160-1.el7_3.1.x86_64
2:vim-common-7.4.160-1.el7_3.1.x86_64
gpm-libs-1.20.7-5.el7.x86_64
2:vim-enhanced-7.4.160-1.el7_3.1.x86_64
Installed:
vim-enhanced.x86_64 2:7.4.160-1.el7_3.1
Dependency Installed:
gpm-libs.x86_64 0:1.20.7-5.el7
vim-common.x86_64 2:7.4.160-1.el7_3.1
vim-filesystem.x86_64 2:7.4.160-1.el7_3.1
Complete!"
]
}
```
## Modules de gestion de code
* git
* subversion
* hg
Ces modules permettent de cloner des dépôts de code.
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_source_control_modules.html</small>
## Modules de gestion du système
<small>https://docs.ansible.com/ansible/2.9/modules/list_of_system_modules.html</small>
<!-- .slide: data-state="small-table" -->
### Utilisateurs et groupes
Module (2.9) | Module (2.10) | Description
- | - | -
`user` | `ansible.builtin.user` | Manage user accounts
`group` | `ansible.builtin.group` | Add or remove groups
<!-- .slide: data-state="small-table" -->
### Stockage
Module (2.9) | Module (2.10) | Description
- | - | -
`parted` | `community.general.parted` | Configure block device partitions
`lvg` | `community.general.lvg` | Configure LVM volume groups
`lvol` | `community.general.lvol` | Configure LVM logical volumes
`filesystem` | `community.general.filesystem` | Makes a filesystem
<!-- .slide: data-state="small-table" -->
### Services
Module (2.9) | Module (2.10) | Description
- | - | -
`service` | `ansible.builtin.service` | Manage services
`service_facts` | `ansible.builtin.service_facts` | Return service state information as fact data
`systemd` | `ansible.builtin.systemd` | Manage services
`sysvinit` | `ansible.builtin.sysvinit` | Manage SysV services
<!-- .slide: data-state="small-table" -->
### Réseau
Module (2.9) | Module (2.10) | Description
- | - | -
`ping` | `ansible.builtin.ping` | Try to connect to host, verify a usable python and return pong on success
`hostname` | `ansible.builtin.hostname` | Manage hostname
`firewalld` | `ansible.posix.firewalld` | Manage arbitrary ports/services with firewalld
`iptables` | `ansible.builtin.iptables` | Modify the systems iptables
<!-- .slide: data-state="small-table" -->
### Configuration SSH
Module (2.9) | Module (2.10) | Description
- | - | -
`authorized_key` | `ansible.posix.authorized_key` | Adds or removes an SSH authorized key
`known_hosts` | `ansible.builtin.known_hosts` | Add or remove a host from the known_hosts file
### Divers
<!-- .slide: data-state="small-table" -->
Module (2.9) | Module (2.10) | Description
- | - | -
`cron` | `ansible.builtin.cron` | Manage cron.d and crontab entries
`reboot` | `ansible.builtin.reboot` | Reboot a machine
`setup` | `ansible.builtin.setup` | Gathers facts about remote hosts
`timezone` | `community.general.timezone` | Configure timezone setting
### Exemple
<!-- .slide: data-state="small-code" -->
Récupération des _facts_ de machines distantes
```none
$ ansible -m setup 'formation'
10.6.214.70 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.6.214.70"
],
"ansible_all_ipv6_addresses": [
"fe80::250:56ff:fe9d:1ae5"
],
"ansible_architecture": "x86_64",
"ansible_bios_date": "09/17/2015",
"ansible_bios_version": "6.00",
"ansible_cmdline": {
"BOOT_IMAGE": "/vmlinuz-3.10.0-327.28.3.el7.x86_64",
"LANG": "fr_FR.UTF-8",
"crashkernel": "auto",
"quiet": true,
"rd.lvm.lv": "rootvg/slashlv",
"rhgb": true,
```

578
Pepiniere/Pepinière/ansible/4.playbooks.md

@ -0,0 +1,578 @@
<!-- .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>

409
Pepiniere/Pepinière/ansible/5.roles.md

@ -0,0 +1,409 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Roles Ansible
Les Roles permettent d'organiser les instructions Ansible de manière à favoriser leur ré-utilisabilité.
![Schéma archi globale](images/ansible-archi-roles.png)
## Qu'est-ce qu'un Role ?
* Un Role Ansible défini une action précise telle que :
- Installer et configurer un serveur Apache
- Installer et configurer un serveur Mariadb
* Un Role Ansible peut être appelé dans un ou plusieurs Playbook.
## Avantages des Roles
* Organisation
- Découpage en plusieurs dossiers et fichiers
- Facilite la compréhension et la maintenance du code.
* Ré-utilisabilité
- Les Roles peuvent facilement être ré-utilisés au sein de plusieurs Playbooks.
* Partage
- Les Roles peuvent être partagés sous la forme de catalogues.
## Organisation d'un Role
<!-- .slide: data-state="small-code" -->
```none
roles/
├── my-role
   ├── README.md
   ├── defaults <= Variables par défaut du Role
     └── main.yaml
   ├── files <= Fichiers pouvant être déployés par le Role
     └── my-file.yaml
   ├── handlers <= Handlers à exécuter
     └── main.yaml
   ├── meta <= Métadonnées sur le Role
     └── main.yaml
   ├── tasks <= Tâches à exécuter
     └── main.yaml
   └── templates <= Templates de fichiers
   │ └── my-template.j2
   └── vars <= Autres variables pour le Role
   └── main.yaml
```
* Un Role doit inclure au minimum un des dossiers suivants
`defaults`, `files`, `handlers`, `tasks`, `templates`, `vars`.
* Si un dossier est déclaré, il doit contenir au minimum un fichier nommé `main.yaml`.
## Utiliser un Role
La méthode classique est la suivante :
`playbook.yaml`
```yaml
- hosts: my-group-of-servers
roles:
- my-role-1
- my-role-2
```
## Ordre d'exécution des tâches
L'ordre d'exécution des tâches
dans un Playbook est le suivant :
1. Tâches définies dans `pre_tasks`
2. Handlers déclenchés jusque là
3. Tâches définies dans `roles`
4. Tâches définies dans le playbook (`tasks`)
5. Handlers déclenchés jusque là
6. Tâches définies dans `post_tasks`
7. Handlers déclenchés jusque là
## pre_tasks, post_tasks
* _tasks_
Tâches définies dans la section `tasks`. Elles sont lancées après les Rôles et avant les tâches définies dans `post_tasks`.
* _pre_tasks_
Tâches lancées avant les Rôles.
* _post_tasks_
Tâches lancées après les tâches de la section `tasks`
(et donc après les Rôles).
## Exemple
Définition de pre_tasks, roles, tasks et post_tasks.
<!-- .slide: data-state="small-code" -->
```yaml
- hosts: ansible-1
pre_tasks:
- name: Pre tasks
debug:
msg: 'I am executed before the Roles.'
roles:
- my-role
tasks:
- name : Tasks
debug:
msg: 'I am executed right after the Roles and just before the Post Tasks.'
post_tasks:
- name: Post tasks
debug:
msg: 'I am executed after the main Tasks.'
```
L'ordre de déclaration n'a pas d'importance.
## Ordre réel d'exécution
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook -v -i inventories/formation/hosts my-playbook.yaml
PLAY [ansible-1] *******************************************************
TASK [Pre tasks] ***************************************************************
ok: [ansible-1] => {
"msg": "I am executed before the Roles."
}
TASK [my-role : Role] **********************************************************
ok: [ansible-1] => {
"msg": "I am running after Pre Tasks and before Tasks."
}
TASK [Tasks] *******************************************************************
ok: [ansible-1] => {
"msg": "I am executed right after the Roles and just before the Post Tasks."
}
TASK [Post tasks] **************************************************************
ok: [ansible-1] => {
"msg": "I am executed after the main Tasks."
}
...
```
## Exemple de découpage en Roles
`playbook.yaml`
```yaml
- hosts: web
roles:
- apache
- wordpress
```
Le Playbook exécute les Roles `apache` et `wordpress`.
### Tâches du Role apache
<!-- .slide: data-state="medium-code" -->
`roles/install-apache/tasks/install.yaml`
```yaml
- name: Installation of Apache Package
yum:
name: httpd
state: present
update_cache: yes
- name: Ensure Apache is running (and enable it at boot)
service:
name: httpd
state: started
enabled: yes
```
### Tâches du Role apache (suite)
<!-- .slide: data-state="medium-code" -->
`roles/configure-apache/tasks/configure.yaml`
```yaml
- name: Modify permission of directory {{ app_directory }}
file:
dest: '{{ app_directory }}'
mode: 0755
owner: '{{ app_user }}'
group: '{{ app_group }}'
recurse: yes
- name: Modify Apache configuration
lineinfile:
dest: /etc/httpd/conf/httpd.conf
regexp: '^Listen '
line: 'Listen {{ apache_listen_port }}'
notify: Reload Apache
```
### Variables du Role apache
<!-- .slide: data-state="medium-code" -->
`roles/configure-apache/vars/main.yaml`
```yaml
apache_listen_port: 8081
app_directory: /var/www/html
app_user: apache
app_group: apache
```
### Handlers du Role apache
<!-- .slide: data-state="medium-code" -->
`roles/configure-apache/handlers/main.yaml`
```yaml
- name: Reload Apache
service:
name: httpd
state: reloaded
```
### Exécution du playbook
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook -i ./hosts playbook.yaml
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [web1.formation.sii.fr]
ok: [web2.formation.sii.fr]
TASK [apache : Installation of Apache Package] *********************************
ok: [web2.formation.sii.fr]
ok: [web1.formation.sii.fr]
TASK [apache : Ensure Apache is running (and enable it at boot)] ***************
ok: [web1.formation.sii.fr]
ok: [web2.formation.sii.fr]
TASK [apache : Modify permission of directory /var/www/html] *******************
ok: [web1.formation.sii.fr]
ok: [web2.formation.sii.fr]
TASK [apache : Modify Apache configuration] ************************************
changed: [web1.formation.sii.fr]
changed: [web2.formation.sii.fr]
RUNNING HANDLER [apache : Reload Apache] ***************************************
changed: [web1.formation.sii.fr]
changed: [web2.formation.sii.fr]
PLAY RECAP *********************************************************************
web1.formation.sii.fr : ok=6 changed=2 unreachable=0 failed=0
web2.formation.sii.fr : ok=6 changed=2 unreachable=0 failed=0
```
Les Roles sont exécutés séquentiellement.
## Importer des fichiers de tâches
* Dans un Role le fichier `tasks/main.yaml` peut appeler d'autres fichiers contenant des tâches avec `import_tasks` ou `include_tasks`.
* Exemple :
`roles/my-role/tasks/main.yaml`
```yaml
tasks:
- import_tasks: install.yaml
- import_tasks: configure.yaml
# ou
- include_tasks: install.yaml
- include_tasks: configure.yaml
```
## Gérer un import par type d'OS
* L'import de tâches permet notamment de gérer les différences d'implémentations entre systèmes.
* Exemple :
`roles/my-role/tasks/main.yaml`
```yaml
- name: specific redhat/centos tasks
import_tasks: redhat.yaml
when: ansible_facts['os_family']|lower == 'redhat'
- name: specific debian/ubuntu tasks
import_tasks: debian.yaml
when: ansible_facts['os_family']|lower == 'debian'
```
`roles/my-role/tasks/redhat.yaml`
```yaml
- yum:
name: "httpd"
state: present
```
`roles/my-role/tasks/debian.yaml`
```yaml
- apt:
name: "apache2"
state: present
```
Il est possible de passer des variables aux tâches importées :
```yaml
tasks:
- import_tasks: wordpress.yaml
vars:
wp_user: bob
```
## Exécution partielle d'un Playbook
<!-- .slide: data-state="medium-code" -->
* L'utilisation de _tags_ permet l'exécution ciblée d'un sous-ensemble de tâches.
```yaml
- hosts: web
roles:
- { role: install-apache, tags: install }
- { role: configure-apache, tags: [install, configure] }
```
* Lors du lancement du playbook, le ciblage s'effectue avec `--tags` ou `--skip-tags`.
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook playbook.yaml -i ./hosts --tags configure
PLAY [web] *********************************************************************
TASK [setup] *******************************************************************
ok: [web1.formation.sii.fr]
ok: [web2.formation.sii.fr]
TASK [configure-apache : Modify permission of directory /var/www/html] *********
changed: [web1.formation.sii.fr]
changed: [web2.formation.sii.fr]
TASK [configure-apache : Modify Apache configuration] **************************
changed: [web1.formation.sii.fr]
changed: [web2.formation.sii.fr]
RUNNING HANDLER [configure-apache : Reload Apache] *****************************
changed: [web1.formation.sii.fr]
changed: [web2.formation.sii.fr]
PLAY RECAP *********************************************************************
web1.formation.sii.fr : ok=4 changed=3 unreachable=0 failed=0
web2.formation.sii.fr : ok=4 changed=3 unreachable=0 failed=0
```
## Dépendances entre Roles
* Un Role peut dépendre d'un ou plusieurs autres Roles.
* Les dépendances d'un Role peuvent être indiquées dans le fichier : `roles/mon-role/meta/main.yaml`
`roles/my-appli/meta/main.yaml`
```yaml
dependencies:
- role: common
- role: apache
vars:
apache_port: 80
```
* Ici les Roles `common` et `apache` seront exécutés
avant le role `mon-appli`.
* Attention : les Roles marqués en dépendances
seront exécutés sur les mêmes machines cibles
que le Role `mon-appli`.
## Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible : roles](travaux-pratiques/tp-ansible-roles.html)</small>

385
Pepiniere/Pepinière/ansible/6.structures-de-controle.md

@ -0,0 +1,385 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Structures de contrôle
## _Facts_
* Variables délivrées par le système distant :
- Adresses IP
- Système d'exploitation
- ...
## Facts - module setup
* Liste des informations disponibles : module _setup_
<!-- .slide: data-state="medium-code" -->
```none
$ ansible my-host -i ./hosts -m setup
my-host | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.6.214.74"
],
"ansible_all_ipv6_addresses": [
"fe80::250:56ff:fe9d:1aaa"
],
"ansible_architecture": "x86_64",
...
```
### Facts pour la gestion multi-os
* `ansible_pkg_mgr` : Le gestionnaire de paquets
* `ansible_os_family` : La famille d'OS
* `ansible_distribution` : Information détaillées sur la distribution
### Gestionnaire de paquets
<!-- .slide: data-state="medium-code" -->
```none
$ ansible my-host -i ./hosts -m setup | grep ansible_pkg_mgr
"ansible_pkg_mgr": "yum",
```
### Famille d'OS
<!-- .slide: data-state="medium-code" -->
```none
$ ansible my-host -i ./hosts -m setup | grep ansible_family
"ansible_os_family": "RedHat",
```
### Distribution
<!-- .slide: data-state="medium-code" -->
```none
$ ansible my-host -i ./hosts -m setup | grep ansible_distribution
"ansible_distribution": "CentOS",
"ansible_distribution_file_parsed": true,
"ansible_distribution_file_path": "/etc/redhat-release",
"ansible_distribution_file_variety": "RedHat",
"ansible_distribution_major_version": "7",
"ansible_distribution_release": "Core",
"ansible_distribution_version": "7.5.1804",
```
### Exemple d'aiguillage multi-OS
<!-- .slide: data-state="small-code" -->
Arborescence du rôle
```none
my-role
├── README.md
├── tasks
   ├── CentOS.yaml -> RedHat.yaml
   ├── Debian.yaml
   ├── main.yaml
   ├── RedHat.yaml
   └── Ubuntu.yaml -> Debian.yaml
└── vars
   ├── CentOS-6.yaml
   ├── CentOS-7.yaml
   ├── Debian-8.yaml
   ├── Debian-9.yaml
   ├── RedHat-6.yaml
   ├── RedHat-7.yaml
   └── Ubuntu-16.yaml
```
<!-- .slide: data-state="medium-code" -->
`my-role/tasks/main.yaml`
```yaml
- name: Add the OS specific variables
include_vars: '{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yaml'
- include_tasks: '{{ansible_distribution}}.yaml'
```
## Utilisation des _conditionals_
* Action déclenchée de manière conditionnelle
(en fonction du résultat d’une variable).
* Utilisation de _when_.
<small>https://docs.ansible.com/ansible/playbooks_conditionals.html</small>
### Exemple
<!-- .slide: data-state="small-code" -->
```yaml
- hosts: web
tasks:
- name: Install Apache for CentOS system
yum:
name: httpd
state: present
update_cache: yes
when:
- ansible_os_family == "RedHat" # sera joué sur RedHat et Centos
- name: Install Apache for Ubuntu system
apt:
name: apache2
state: present
update_cache: yes
when:
- ansible_os_family == "Debian" # sera joué sur Debian et Ubuntu
```
Chaque tâche cible une famille
de système d'exploitation précise.
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook playbook.yaml -i ./hosts
PLAY [web] *******************************************************************
TASK [setup] *****************************************************************
ok: [centos-vm]
ok: [ubuntu-vm]
TASK [Install Apache for CentOS system] **************************************
ok: [centos-vm]
skipping: [ubuntu-vm]
TASK [Install Apache for Ubuntu system] **************************************
skipping: [centos-vm]
ok: [ubuntu-vm]
PLAY RECAP *******************************************************************
centos-vm : ok=2 changed=0 unreachable=0 failed=0
ubuntu-vm : ok=2 changed=0 unreachable=0 failed=0
```
Les tâches sont exécutées ou non en fonction
de la famille du système d'exploitation.
## Utilisation des _loops_
* Boucles pour la réalisation d'actions répétitives.
* Permet de faire plusieurs actions dans une seule tâche.
* Création d'utilisateurs, installation de paquets, ...
* Utilisation de ~~with-x~~ _loop_
<small>https://docs.ansible.com/ansible/playbooks_loops.html</small>
### with-x
<!-- .slide: data-state="small-table" -->
Paramètre | Type | Example d'utilisation
- | - | -
`with_items` | Array | To create a group of users, directories, or to install a list of packages
`with_nested` | Nested loops | To create a list of MySQL users and grant them access to a group of databases
`with_dict` | Hashes | To parse a dictionary of key-value pairs and create virtual hosts
`with_fileglobs` |Files with pattern match | To parse a path and copy only those files that match a certain pattern
`with_together` | S ets | To join two arrays as a set and to loop over it
`with_subelements` | Hash sub element | To walk over the list of SSH keys and distribute them to a user
`with_sequence` | Integer sequence | To loop a sequence of numbers
`with_random_choice` | Random choice | To pick up items from the array in a random order
`with_indexed_items` | Array with index | Array with an index and is useful when an index for items is required
### Exemple avec with_items
```yaml
- hosts: my-host
tasks:
- name: Add some users
user:
name: "{{ item }}"
state: present
with_items:
- bob
- alice
- joe
```
Attention ! à partir d'Ansible 2.5 _with-x_ n'est plus la méthode recommandé pour effectué des boucles.
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook playbook.yaml -i ./hosts
PLAY [my-host] ***************************************************************
TASK [setup] *****************************************************************
ok: [my-host]
TASK [Add some users] ********************************************************
changed: [my-host] => (item=bob)
changed: [my-host] => (item=alice)
changed: [my-host] => (item=joe)
PLAY RECAP *******************************************************************
my-host : ok=2 changed=1 unreachable=0 failed=0
```
La boucle a bien itéré sur les 3 utilisateurs.
### Migration vers loop
* A partir d'Ansible 2.5 _with-x_ n'est plus la méthode recommandée pour effectuer des boucles.
* La documentation sur les boucles propose une section pour aider à la migration de _with-x_ vers _loop_.
<small>https://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html</small>
### Exemple avec loop
```yaml
- hosts: my-host
tasks:
- name: Add some users
user:
name: "{{ item }}"
state: present
loop:
- bob
- alice
- joe
```
On remplace simplement `with_items` par `loop`.
<!-- .slide: data-state="small-code" -->
```none
$ ansible-playbook -i inventories/formation/hosts playbook.yaml
PLAY [my-host] ***************************************************************
TASK [Gathering Facts] *******************************************************
ok: [my-host]
TASK [Add some users] ********************************************************
changed: [my-host] => (item=bob)
changed: [my-host] => (item=alice)
changed: [my-host] => (item=joe)
PLAY RECAP *******************************************************************
my-host : ok=2 changed=1 unreachable=0 failed=0
```
Le résultat final est strictement identique.
```yaml
- hosts: my-host
tasks:
- name: Add some users
user:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name: 'bob', groups: 'wheel' }
- { name: 'alice', groups: 'root' }
- { name: 'joe', groups: 'root' }
```
En plus des _strings_ , il est possible d'utiliser des _hashes_.
### Itérer sur l'inventaire
<!-- .slide: data-state="small-code" -->
```yaml
- hosts: centos7
tasks:
- name: Iterate on hosts in the group all in the inventory
debug:
msg: "{{ item }}"
loop: "{{ groups['all'] }}" # on itère sur les machines du groupe all
```
```none
$ ansible-playbook -i ./hosts playbook.yaml
PLAY [centos7] *****************************************************************
TASK [Iterate on hosts in the group all in the inventory] **********************
ok: [ansible-1] => (item=ansible-3) => {
"msg": "ansible-3"
}
ok: [ansible-1] => (item=ansible-1) => {
"msg": "ansible-1"
}
ok: [ansible-1] => (item=ansible-2) => {
"msg": "ansible-2"
}
ok: [ansible-2] => (item=ansible-3) => {
"msg": "ansible-3"
}
ok: [ansible-2] => (item=ansible-1) => {
"msg": "ansible-1"
}
ok: [ansible-2] => (item=ansible-2) => {
"msg": "ansible-2"
}
```
Chaque machine du Play (_centos7_) itère sur le groupe _all_.
### Itérer sur le Play
<!-- .slide: data-state="small-code" -->
```yaml
- hosts: centos7
tasks:
- name: Iterate on all the hosts in the current play
debug:
msg: "{{ item }}"
loop: "{{ ansible_play_batch }}" # variable qui contient les machines du Play
```
```none
$ ansible-playbook -i inventories/formation/hosts playbook.yaml
PLAY [centos7] *****************************************************************
TASK [Iterate on all the hosts in the current play] ****************************
ok: [ansible-1] => (item=ansible-1) => {
"msg": "ansible-1"
}
ok: [ansible-1] => (item=ansible-2) => {
"msg": "ansible-2"
}
ok: [ansible-2] => (item=ansible-1) => {
"msg": "ansible-1"
}
ok: [ansible-2] => (item=ansible-2) => {
"msg": "ansible-2"
}
```
Chaque machine du Play (_centos7_) itère
sur les machines du Play (_centos7_).
## Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible : structures de contrôle](travaux-pratiques/tp-ansible-structures-de-controle.html)</small>

516
Pepiniere/Pepinière/ansible/7.templates.md

@ -0,0 +1,516 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Templates
## Syntaxe jinja2
* Documentation
- Jinja language :
http://jinja.pocoo.org/docs/
- Template formatting :
http://jinja.pocoo.org/docs/templates/
## Principe
* On créé les fichiers dans le dossier `templates` du Role.
* On indique l'emplacement des zones variables à l'aide de la syntaxe `{{ ma_variable }}`.
`templates/httpd.conf.j2`
```none
...
Listen {{ apache_port }}
DocumentRoot {{ apache_document_root }}
ServerName {{ apache_server_name }}
ServerAdmin {{ apache_server_admin }}
...
```
On utilise le module _template_
<!-- .slide: data-state="medium-code" -->
```yaml
- hosts: web
vars:
apache_port: 80
apache_document_root: /var/www/html
apache_server_name: my-server
apache_server_admin: admin@localhost
tasks:
- name: Deploy Apache configuration
template:
src: templates/httpd.conf.j2
dest: /etc/http/httpd.conf
owner: apache
group: apache
mode: 0600
```
Les variables sont automatiquement injectées dans le fichier sur la cible.
## Exemple pour une configuration du service NTP
<!-- .slide: data-state="small-code" -->
`./group_vars/all`
```none
ntp_servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
- 3.pool.ntp.org
```
`./roles/ntp/templates/ntp.conf.j2`
```none
...
{% for server in ntp_servers %}
server {{ server }}
{% endfor %}
...
```
`./roles/ntp/tasks/main.yaml`
```yaml
- name: Install NTP package
apt:
name: "ntp"
- name: Configure NTP
template:
src: ntp.conf.j2
dest: "/etc/ntp.conf"
owner: "root"
group: "root"
mode: 0644
notify: Restart ntp service
```
## Contrôle conditionnel
```none
{% if condition %}
do_some_thing
{% elif condition2 %}
do_another_thing
{% else %}
do_something_else
{% endif %}
```
## Filtres
Les variables peuvent être modifiées par des filtres.
<small>https://docs.ansible.com/ansible/playbooks_filters.html</small>
### Filtres Jinja2
* Les filtres Ansible reposent sur Jinja2.
* Ils sont utilisés pour transformer des données.
* Les filtres peuvent être chaînés.
* Il est possible de créer des filtres personnalisés.
### Fixer une valeur par défaut aux variables non-définies
```none
{{ variable | default(5) }}
```
### Formater des données
```none
{{ variable | to_json }}
{{ variable | to_yaml }}
```
```none
{{ variable | from_json }}
{{ variable | from_yaml }}
```
### Filtres de listes
Récupérer les valeurs minimales ou maximales
```none
{{ ma_liste | min }}
{{ [3, 4, 2] | max }}
```
Eliminer les doublons
```none
{{ list1 | unique }}
```
Combiner deux listes
```none
{{ list1 | union(list2) }}
```
Obtenir la différence entre deux listes (éléments dans list1 qui n'existent pas dans list2)
```none
{{ list1 | difference(list2) }}
```
### Filtres de nombres aléatoires
Obtenir un élément au hasard parmi une liste
```none
"{{ ['a','b','c'] | random }}"
# => 'c'
```
Obtenir un nombre au hasard entre 0 et une valeur spécifiée
```none
"{{ 60 | random}} * * * * root /script/from/cron“
# => '21 * * * * root /script/from/cron'
```
Obtenir un nombre au hasard entre 0 et 100 par pas de 10
```none
{{ 101 | random(step=10) }}
# => 70
```
### Tester des adresses IP
Tester si une chaîne est une adresse IP valide
```none
{{ myvar | ipaddr }}
```
Même chose en forçant la version du protocole IP
```none
{{ myvar | ipv4 }}
{{ myvar | ipv6 }}
```
### Filtres sur la notation CIDR
```none
{{ '192.0.2.1/24' | ipaddr('address') }}
'192.0.2.1/24'
```
```none
{{ '192.0.2.1/24' | ipaddr('prefix') }}
'24'
```
<small>https://docs.ansible.com/ansible/playbooks_filters_ipaddr.html</small>
### Fonctions de hashage
Obtenir l'empreinte sha1 ou md5 d'une chaîne
```none
{{ 'test1' | hash('sha1') }}
'dba7673010f19a94af4345453005933fd511bea9'
{{ 'test1' | hash('md5') }}
'3e7705498e8be60520841409ebc69bc1'
```
<small>https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html#hashing-filters</small>
<!-- .slide: data-state="medium-code" -->
Obtenir un hashage de mot de passe sha512
```none
{{ 'passwordsaresecret' | password_hash('sha512') }}
```
Obtenir un hashage de mot de passe sha256 avec salage
```none
{{ 'secretpassword' | password_hash('sha256', 'mysecretsalt') }}
```
Exemple d'utilisation dans un fichier de variables
```none
user_password: "{{ 'Mon super password' | password_hash('sha256') }}"
```
### Filtres de commentaires
Il permettent de "décorer" un texte
avec un style de commentaire.
Exemple :
```none
{{ "Hello" | comment }}
```
produit :
```none
#
# Hello
#
```
Il est possible d'appliquer
différents types de commentaires :
```none
{{ "C style" | comment('c') }}
'// C style'
```
```none
{{ "C block style" | comment('cblock') }}
'/* C block style */'
```
```none
{{ "XML style" | comment('xml') }}
'<!--XML style-->'
```
### Filtres d'URL
<!-- .slide: data-state="small-code medium-table" -->
Obtenir une sous-partie d'une URL.
```none
{{ "http://bob:1234@www.test.com:81/dir/index.html?query=term#fragment"
| urlsplit('scheme') }}
# => 'http'
```
Filtre | Résultat
- | -
urlsplit('scheme') | 'http'
urlsplit('username') | 'bob'
urlsplit('password') | '1234'
urlsplit('hostname') | 'www.test.com'
urlsplit('port') | '81'
urlsplit('path') | '/dir/index.html'
urlsplit('query') | 'query=term'
urlsplit('fragment') | 'fragment'
### Autres filtres utiles
Ajouter des guillemets pour protéger des variables
(usage shell)
```none
- shell: echo {{ string_value | quote }}
```
Retourner une valeur si un test est vrai
et une autre si il est faux
```none
{{ (name == "John") | ternary('Mr','Mme') }}
```
Concatener une liste en chaîne
```none
{{ list | join(" ") }}
```
```none
{{ list | join(",") }}
```
Obtenir le dernier élément d'un chemin
```none
{{ '/etc/foo/bar.txt' | basename }}
'bar.txt'
```
Obtenir le début d'un chemin
```none
{{ '/etc/foo/bar.txt' | dirname }}
'/etc/foo'
```
Obtenir le chemin réel d'un lien
```none
{{ path | realpath }}
```
Expanser un chemin contenant un tilde (~)
```none
{{ path | expanduser }}
```
Expanser un chemin contenant des variables d'environnement
```none
{{ path | expandvars }}
```
Découper un nom de fichier
```none
{{ path | splitext }}
```
Avec `path` == `nginx.conf` le retour sera `('nginx', '.conf')`
## Tests
`variable` is `test expression`
<small>https://docs.ansible.com/ansible/playbooks_tests.html</small>
### Tester des chaînes de caractères
<!-- .slide: data-state="small-code" -->
```yaml
vars:
url: "http://example.com/users/foo/resources/bar"
tasks:
- debug:
msg: "matched pattern 1"
when: url is match("http://example.com/users/.*/resources/.*")
- debug:
msg: "matched pattern 2"
when: url is search("/users/.*/resources/.*")
- debug:
msg: "matched pattern 3"
when: url is search("/groups/")
```
```none
TASK [debug] *****************************************************************
ok: [my-host] => { "msg": "matched pattern 1" }
TASK [debug] *****************************************************************
ok: [my-host] => { "msg": "matched pattern 2" }
TASK [debug] *****************************************************************
skipping: [my-host]
```
### Tester des numéros de version
Si `ansible_facts['distribution_version']` est supérieur ou égal à 16.04, le test retourne `True`, sinon il retourne `False`.
<!-- .slide: data-state="medium-code" -->
```none
{{ ansible_facts['distribution_version'] is version('16.04', '>=') }}
```
Opérateurs acceptés :
`<`, `lt`, `<=`, `le`, `>`, `gt`, `>=`, `ge`, `==`, `=`, `eq`, `!=`, `<>`, `ne`
### Tester des chemins
<!-- .slide: data-state="small-code" -->
```yaml
- debug:
msg: "path is a directory"
when: mypath is directory
- debug:
msg: "path is a file"
when: mypath is file
- debug:
msg: "path is a symlink"
when: mypath is link
- debug:
msg: "path already exists"
when: mypath is exists
```
Chaque tâche est effectuée ou abandonnée
en fonction du résultat du test.
### Tester le résultat final d'une tâche
```yaml
- shell: /usr/bin/foo
register: result
ignore_errors: True
- debug:
msg: "it failed"
when: result is failed
- debug:
msg: "it succeeded"
when: result is succeeded
```
## Sortir prématurément en fonction de conditions
* Le module _fail_ permet de stopper l'exécution d'un playbook si un condition n'est pas remplie.
* Dans l'exemple suivant, l'exécution s'arrête car la variable `param2` n'est pas définie.
<!-- .slide: data-state="medium-code" -->
```yaml
---
- hosts: ansible-1
vars:
- param1: "test"
tasks:
- name: 'exit if param1 or param2 are null or invalid'
fail: msg="Please enter correct Params"
when: param1 is not defined or param2 is not defined
- debug:
msg: "other tasks..."
```
## Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible : templates](travaux-pratiques/tp-ansible-templates.html)</small>

306
Pepiniere/Pepinière/ansible/8.notions-avancees.md

@ -0,0 +1,306 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# ansible-vault
Sécuriser les données sensibles.
* La commande `ansible-vault` permet la création de conteneurs chiffrés pour les variables sensibles.
```nohighlight
$ ansible-vault create test.yaml
Vault password:
```
* Le choix d'un un mot de passe est obligatoire lors de la création du fichier.
<!-- .slide: data-state="small-code" -->
Le contenu en clair :
```nohighlight
mon_super_mot_de_passe: 12345678
```
devient après chiffrement :
```nohighlight
$ cat test.yaml
$ANSIBLE_VAULT;1.1;AES256
62366463643661313763313135376434303535646637653237633233306663623635643761643161
3834383236386535366533303733613838653836623661340a383263633435336234333335343539
30333664666364613731666666636235373633346463353766356364623039656262363238363830
3236656664353565620a303034643732636166376535386436616231653363386334663065326337
3561
```
Le mot de passe sera demandé lors de chacune des exécutions du playbook :
```nohighlight
$ ansible-playbook mon-playbook.yaml –ask-vault-pass
Vault password:
```
### Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible vault](travaux-pratiques/tp-ansible-vault.html)</small>
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Notions avancées
## Surcharge de variables
* Ansible permet la déclaration de variables en de multiples endroits.
* Ansible supporte la surcharge de variables, cette surcharge dépend de l’endroit où les variables sont déclarées.
Ordre de priorité croissant lors de la surcharge :
<small>
* role defaults
* inventory file or script group vars
* inventory group_vars/all
* playbook group_vars/all
* inventory group_vars/*
* playbook group_vars/*
* inventory file or script host vars
* inventory host_vars/*
* playbook host_vars/*
* host facts / cached set_facts
* play vars
* play vars_files
* role vars (defined in role/vars/main.yaml)
* task vars (only for the task)
* include_vars
* set_facts / registered vars
* role (and include_role) params
* include params
* extra vars (always win precedence)
</small>
## register + debug + verbosity
<!-- .slide: data-state="medium-code" -->
```yaml
- shell: /usr/bin/uptime
register: result
- name: Display uptime
debug:
var: result
verbosity: 2 # affiché à partir du niveau -vv
- name: Display all variables/facts known for a host
debug:
var: hostvars[inventory_hostname]
verbosity: 4 # affiché à partir du niveau -vvvv
```
## Niveau de verbosité
```nohighlight
$ ansible-playbook -i ./hosts playbook.yaml
```
```nohighlight
$ ansible-playbook -vv -i ./hosts playbook.yaml
```
```nohighlight
$ ansible-playbook -vvvv -i ./hosts playbook.yaml
```
## Check mode (« Dry Run »)
* Simulation de l'exécution d'un Playbook.
* Aucun changement n'est effectué sur les hosts lors du check.
* Utiliser l’option `--check`.
* _Attention_ ! Certains modules sont incompatibles avec le Check mode.
Forcer ou non une tâche en check : `check_mode: yes/no`
<!-- .slide: data-state="small-code" -->
```yaml
tasks:
- name: this task will make changes to the system even in check mode
command: /something/to/run --even-in-check-mode
check_mode: no
- name: this task will always run under checkmode and not change the system
lineinfile:
line: "important config"
dest: /path/to/myconfig.conf
state: present
check_mode: yes
```
## Autres options de ansible-playbook
<!-- .slide: data-state="medium-table" -->
Option | Description
- | -
`--list-hosts` | Affiche les machines concernées par le Play
`--list-tags` | Affiche les tags disponibles
`--list-tasks` | Affiche les tâches qui seront exécutées
`--step` | Demande confirmation avant l'exécution de chaque tâche
`--syntax-check` | Analyse syntaxique du Playbook (sans l'exécuter)
## Tester du code Ansible
![Logo Molecule](images/logo-molecule.png) <!-- .element: width="150px" -->
* Permet de tester des Roles Ansible
<small>https://molecule.readthedocs.io/en/latest/</small>
![Logo TestInfra](images/logo-testinfra.svg) <!-- .element: width="150px" -->
Création de tests unitaire en langage Python
<!-- .slide: data-state="small-table" -->
```python
def test_passwd_file(host):
passwd = host.file("/etc/passwd")
assert passwd.contains("root")
assert passwd.user == "root"
assert passwd.group == "root"
assert passwd.mode == 0o644
```
Combiné avec GitLab-CI/Jenkins et Docker, il permet d'automatiser le test de code Ansible.
<small>https://testinfra.readthedocs.io/en/latest/</small>
## Ansible Lint
* Permet de détecter les comportements et les pratiques qui peuvent être améliorés.
<small>https://ansible-lint.readthedocs.io/en/latest/</small>
## Ansible en mode Pull
* Ansible fonctionne traditionnellement en mode `Push`.
* Il est possible de passer en mode `Pull` à l'aide de la commande `ansible-pull`.
* Intérêt du mode Pull
- Adresser un grand nombre de machines,
- Remediation des systèmes en continu.
* Pré-requis du mode Pull
* Playbooks disponibles sur un dépôt git,
* Ansible installé sur chaque machine cible.
<small>https://docs.ansible.com/ansible/latest/cli/ansible-pull.html</small>
<small>https://github.com/ansible/ansible-examples/blob/master/language_features/ansible_pull.yaml</small>
## Développer un module personnalisé
`./library/mymodule.py`
```python
#!/usr/bin/python
from ansible.module_utils.basic import *
def main():
module = AnsibleModule(argument_spec={})
response = {"hello": "world"}
module.exit_json(changed=False, meta=response)
if __name__ == '__main__':
main()
```
<small>https://blog.toast38coza.me/custom-ansible-module-hello-world/</small>
<small>https://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html</small>
## Utiliser un module personnalisé
<!-- .slide: data-state="small-code" -->
`playbook-demo-mymodule.yaml`
```yaml
- hosts: web
tasks:
- name: Test that my module works
mymodule:
register: result
- debug: var=result
```
```nohighlight
$ ansible-playbook -i ./hosts playbook-demo-mymodule.yaml
...
TASK [Test that my module works] ***********************************************
ok: [web2.formation.sii.fr]
ok: [web1.formation.sii.fr]
TASK [debug] *******************************************************************
ok: [web1.formation.sii.fr] => {
"result": { "changed": false, "meta": { "hello": "world" } }
}
ok: [web2.formation.sii.fr] => {
"result": { "changed": false, "meta": { "hello": "world" } }
}
...
```
## Ansible Tower
* Interface Web propriétaire pour le lancement de playbooks.
* Accès à l’historique des playbooks lancés et aux logs d'exécution.
* Gestion des utilisateurs et de l'inventaire.
* Pilotable via API.
<small>https://www.ansible.com/products/tower</small>
### Tableau de bord d'Ansible Tower
![Tower dashboard](images/tower-dashboard.png)
### AWX
* Version opensource de Ansible Tower (sous licence Apache 2.0.)
* AWX est à Ansible Tower ce que Fedora est à Red Hat Enterprise Linux.
* Non recommandé pour les environnements de production.
* Aucun support n'est fourni par Red Hat.
<small>https://www.ansible.com/products/awx-project</small>

246
Pepiniere/Pepinière/ansible/9.Ansible-Galaxy.md

@ -0,0 +1,246 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Logo Ansible](images/logo-ansible.svg)
# Ansible Galaxy
Créer et partager ses propres roles.
## Ansible Galaxy
* Communauté pour trouver, télécharger, partager des rôles.
* Site : [https://galaxy.ansible.com/](https://galaxy.ansible.com/)
* CLI : `ansible-galaxy`
* Doc : [http://docs.ansible.com/ansible/galaxy.html](http://docs.ansible.com/ansible/galaxy.html)
## Une communauté
* Télécharger des roles depuis Galaxy est un bon moyen pour démarrer un projet.
* On ne réinvente pas la roue.
* Enormément de projets : environ 19'500 roles (jan. 2019).
## Mais soyez vigilent
* Tout le monde peut partager.
* Beaucoup de duplications.
* Vulnérabilités, malveillance, dangereux, mauvais fonctionnement...
![](images/ansible-galaxy-site.png) <!-- .element: width="2000px" -->
## Rechercher des rôles
<!-- .slide: data-state="small-code" -->
```none
$ ansible-galaxy search httpd
Found 182 roles matching your search:
Name Description
---- -----------
2kloc.trellis-monit Install and configure Monit service in Trellis.
acropia.httpd IT Professional
ahuffman.sat6_create_hosts An Ansible role to create new virtual and ba...
AlbanAndrieu.ansible-workstation A role for installing workstation
AnatolyRugalev.ansistrano-deploy Ansible role to deploy scripting application...
ansiblebit.httpd Ansible role to setup the Apache HTTP server.
ansiblebit.mod_wsgi Ansible role to install and setup mod_wsgi.
ansible-ThoTeam.nexus3-oss Nexus Repository Manager 3.x (Sonatype)
ansistrano.deploy Ansible role to deploy scripting application...
ansistrano.rollback Ansible role to rollback scripting applicati...
Anthony25.squid Installs Squid
archf.packages Ansible role to install packages on a host
awasilyev.apache-container Ansible Container role that adds an apache s...
awasilyev.drupal-container Ansible Container role that adds an apache s...
awasilyev.tomcat-container Ansible Container role that adds an tomcat s...
axmac.axmac_apache Apache2
beardyjay.firewalld Base role for firewalld
...
```
## Télécharger un rôle
* https://galaxy.ansible.com/geerlingguy/apache
<!-- .slide: data-state="small-code" -->
```none
$ ansible-galaxy install geerlingguy.apache
- downloading role 'apache', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role/.../3.0.3.tar.gz
- extracting geerlingguy.apache to /home/ansible/.ansible/roles/geerlingguy.apache
- geerlingguy.apache (3.0.3) was installed successfully
```
## Fichiers récupérés
<!-- .slide: data-state="small-code" -->
```none
/home/ansible/.ansible
└── roles
   └── geerlingguy.apache
   ├── defaults
     └── main.yaml
   ├── handlers
     └── main.yaml
   ├── LICENSE
   ├── meta
     └── main.yaml
   ├── README.md
   ├── tasks
     ├── configure-Debian.yaml
     ├── configure-RedHat.yaml
     ├── configure-Suse.yaml
     ├── main.yaml
     ├── setup-Debian.yaml
     ├── setup-RedHat.yaml
     └── setup-Suse.yaml
   ├── templates
     └── vhosts.conf.j2
   └── vars
   ├── apache-22.yaml
   ├── apache-24.yaml
   ├── Debian.yaml
   ├── RedHat.yaml
   └── Suse.yaml
```
## Pourquoi utiliser Galaxy ?
* Créer des roles Ansible réutilisables est une bonne pratique.
* Partager des roles sur son propre SCM.
* Apporter une notion de dépendances à la sauce Maven ou NPM.
## Fonctionnement avancé
* Installer plusieurs roles en une seule fois.
* Récupérer des roles depuis plusieurs sources (Galaxy, Git, filer...).
* Un seul fichier décrivant la liste des roles à installer : `requirements.yaml`
```none
$ ansible-galaxy install -r requirements.yaml
```
## Plusieurs sources possibles
Depuis Galaxy
<!-- .slide: data-state="medium-code" -->
```yaml
- src: zaxos.tomcat-ansible-role
- src: user.rolename
...
```
Avec l'utilisation de Galaxy, l'attribut `src` représente simplement `<nom du contributeur>`.`<nom du role>`
Depuis un serveur Git
<!-- .slide: data-state="medium-code" -->
```yaml
- src: git@gitlab.sii-ouest.fr:ouest/projects/ansible/tomcat.git
scm: git
version: develop
```
L'attribut `version` peut être un tag, un nom de branche ou un numéro de commit. La version par défaut est master.
Depuis GitHub, pas besoin d'indiquer de SCM
Depuis un serveur web
<!-- .slide: data-state="medium-code" -->
```yaml
- src: https://url.du.serveur.com/ansible/roles/tomcat.tar.gz
name: tomcat-role
```
L'attribut `name` sert à indiquer le nom du role lorsqu'il est téléchargé
## Définir le chemin de téléchargement
<!-- .slide: data-state="medium-code" -->
Par défaut, les roles sont téléchargés à l'endroit spécifié par la variable d'environnement `ANSIBLE_ROLE_PATH`.
Il est possible de définir le chemin directement en ligne de commande.
```none
$ ansible-galaxy install -r requirements.yaml -p|-roles-path .
```
## Créer des roles Ansible
Il est très facile de créer un role Ansible avec une structure de dossier pré-définit avec la commande `init`.
```none
$ ansible-galaxy init tomcat-custom
```
</br>
L'argument `-force` permet d'écraser un role existant portant le même nom.
La création du role génère la structure ci-dessous :
```none
/tomcat-custom
├── README.md
├── .travis.yaml
├── defaults/
| └── main.yaml
├── files/
├── handlers/
| └── main.yaml
├── meta/
| └── main.yaml
├── templates/
├── tests/
| ├── inventory
| └── test.yaml
└── vars/
└──main.yaml
```
## Utiliser une structure personalisée
<!-- .slide: data-state="medium-code" -->
```none
$ ansible-galaxy init --role-skeleton=/chemin/squelette tomcat-custom
```
Quand une structure personalisée est utilisée, les points suivants sont respectés :
* Copie tous les fichiers et dossiers vers le nouveau role.
* Les dossiers `.git` et fichiers `.git_keep` ne sont pas recopiés.
* Le fichier `meta/main.yaml` est obligatoire pour récupérer le role via Galaxy.
### Travaux pratiques
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![Travaux pratiques](images/tp.gif)
<small>[TP Ansible Galaxy](travaux-pratiques/tp-ansible-galaxy.html)</small>

29
Pepiniere/Pepinière/ansible/README.md

@ -0,0 +1,29 @@
# Formation Ansible
## Programme
1. Introduction ansible
2. Installation / Inventaire
3. Commandes ad-hoc
4. Playbooks
5. Roles
6. Structures de contrôle
7. Templates
8. Notions avancées
## Slides
Pour récupérer les slides :
`git clone --recurse-submodules https://gitlab.siinergy.net/sii-ouest/trainings/ansible.git`
Version [pdf](https://gitlab.siinergy.net/sii-ouest/trainings/ansible/-/jobs/artifacts/2019-03-06/raw/ansible.pdf?job=make-pdf)
## Machines vituelles
Voir [ansible-config-virtualbox-vms.md](ansible-config-virtualbox-vms.md).
## Todo
Les améliorations à apporter à la formation : [https://gitlab.siinergy.net/sii-ouest/trainings/ansible/boards](https://gitlab.siinergy.net/sii-ouest/trainings/ansible/boards)

54
Pepiniere/Pepinière/ansible/ansible-config-virtualbox-vms.md

@ -0,0 +1,54 @@
# Machines virtuelles VirtualBox pour la formation Ansible
## Pré-requis de l'hôte
- 8 Go de RAM au minimum
- Processeur Intel Corei__X__
## Machines virtuelles
Un fichier _.ova_ contenant deux machines virtuelles prêtes à l'emploi est disponible sur le filer.
Mot de passe de l'utilisateur `ansible` : `ansible`.
Mot de passe de l'utilisateur `root` : `ansible`.
VM | description
- | -
ansible-0 | Machine ansible maître avec OS Debian 9 et ansible 2.6 installé
ansible-1 | Machine de test avec OS Centos 7
ansible-2 | Machine de test avec OS Centos 7
ansible-3 | Machine de test avec OS Debian 9
### Configuration des ressources
- 1024 Mo RAM par VM
- 1 CPU par VM
### Configuration réseau
Chaque VM a 2 interfaces réseaux :
- Interface 1 : __NAT__
L’accès Internet de la machine hôte est alors partagé, on peut faire des mises à jour etc. La machine virtuelle voit Internet mais n’est pas vue du réseau local (elle est derrière un NAT qui est géré par VirtualBox).
- Interface 2 : __Réseau privé hôte avec DHCP__
La machine est visible et voit la machine hôte et réciproquement. Cette interface réseau sert pour se connecter en SSH depuis la machine hôte sur la machine virtuelle. Elle permet également aux différentes machines virtuelles positionnées sur ce réseau de communiquer entre elles.
Le type des cartes est __Intel PRO/1000 MT Desktop (82540EM)__.
Qui voit quoi ?
- Via la carte en __NAT__
* la VM a accès à Internet pour les mises à jour derrière un NAT.
* La VM est invisible du réseau local et de la machine hôte (à moins de faire des redirections de port).
- Via la carte __Réseau privé hôte__
* la VM a accès à la machine hôte et réciproquement.
* la VM est visible des autres machines virtuelles situées dans le même réseau privé hôte.
En résumé, les deux machines virtuelles pourront donc communiquer entre elles via l'interface _Réseau privé hôte_ et accéder à internet via l'interface _NAT_.
Si besoin que toutes les VMs des stagiaires se voient entre elles il est possible de remplacer la carte __NAT__ par une carte __Bridge__.

BIN
Pepiniere/Pepinière/ansible/images/ansible-ad-hoc-deployment-workflow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-ad-hoc-multi-node-deployment.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-archi-playbooks.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-archi-roles.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-archi-ssh.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-galaxy-site.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-playbook-deployment-workflow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
Pepiniere/Pepinière/ansible/images/ansible-playbook-multi-node-deployment-workflow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

BIN
Pepiniere/Pepinière/ansible/images/ci-vs-cd-devops-difference.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

70
Pepiniere/Pepinière/ansible/images/logo-ansible.svg

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="255.13245"
height="255.13094"
viewBox="0 0 255.13245 255.13094"
version="1.1"
preserveAspectRatio="xMidYMid"
id="svg925"
sodipodi:docname="logo-ansible.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)">
<metadata
id="metadata931">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs929" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1104"
inkscape:window-height="740"
id="namedview927"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.74920635"
inkscape:cx="127.25387"
inkscape:cy="97.93274"
inkscape:window-x="2675"
inkscape:window-y="167"
inkscape:window-maximized="0"
inkscape:current-layer="svg925" />
<g
id="g921"
transform="translate(-0.74612733,-0.30180854)">
<path
style="fill:#1a1918"
inkscape:connector-curvature="0"
id="path917"
d="m 255.87857,127.86803 c 0,70.45514 -57.11008,127.56471 -127.56622,127.56471 -70.450124,0 -127.56622267,-57.10957 -127.56622267,-127.56471 0,-70.450122 57.11609867,-127.56622146 127.56622267,-127.56622146 70.45614,0 127.56622,57.11609946 127.56622,127.56622146" />
<path
style="fill:#ffffff"
inkscape:connector-curvature="0"
id="path919"
d="m 130.45986,78.228885 33.0116,81.476255 -49.86345,-39.2778 z M 189.10434,178.47412 138.32577,56.27205 c -1.44952,-3.524365 -4.34807,-5.389259 -7.86591,-5.389259 -3.52436,0 -6.63386,1.864894 -8.08338,5.389259 L 66.643604,190.31241 h 19.06532 l 22.062306,-55.26527 65.83887,53.18993 c 2.64792,2.14114 4.55852,3.1095 7.0422,3.1095 4.97389,0 9.32146,-3.72879 9.32146,-9.11102 0,-0.87594 -0.3094,-2.2662 -0.86942,-3.76143 z" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
Pepiniere/Pepinière/ansible/images/logo-molecule.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

240
Pepiniere/Pepinière/ansible/images/logo-testinfra.svg

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="69.332382mm"
height="73.924599mm"
viewBox="0 0 69.332382 73.924598"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="logo.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.2198742"
inkscape:cx="152.60272"
inkscape:cy="114.33618"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:window-width="1238"
inkscape:window-height="1149"
inkscape:window-x="678"
inkscape:window-y="24"
inkscape:window-maximized="0"
fit-margin-top="5"
fit-margin-left="5"
fit-margin-right="5"
fit-margin-bottom="5">
<sodipodi:guide
position="34.492814,79.507924"
orientation="1,0"
id="guide131"
inkscape:locked="false" />
<sodipodi:guide
position="37.138654,79.507924"
orientation="1,0"
id="guide133"
inkscape:locked="false" />
<inkscape:grid
type="xygrid"
id="grid135"
originx="-75.309266"
originy="-204.91915" />
<sodipodi:guide
position="31.846984,66.278763"
orientation="-0.70710678,0.70710678"
id="guide137"
inkscape:locked="false" />
<sodipodi:guide
position="46.399065,59.664183"
orientation="0.70710678,0.70710678"
id="guide139"
inkscape:locked="false" />
<sodipodi:guide
position="23.909484,68.924593"
orientation="1,0"
id="guide141"
inkscape:locked="false" />
<sodipodi:guide
position="47.721985,68.924593"
orientation="1,0"
id="guide143"
inkscape:locked="false" />
<sodipodi:guide
position="49.044895,62.310013"
orientation="1,0"
id="guide145"
inkscape:locked="false" />
<sodipodi:guide
position="22.586565,59.664183"
orientation="1,0"
id="guide147"
inkscape:locked="false" />
<sodipodi:guide
position="18.617815,47.757932"
orientation="-0.70710678,0.70710678"
id="guide149"
inkscape:locked="false" />
<sodipodi:guide
position="53.013645,47.757932"
orientation="0.70710678,0.70710678"
id="guide151"
inkscape:locked="false" />
<sodipodi:guide
position="60.951144,25.268352"
orientation="0.70710678,0.70710678"
id="guide153"
inkscape:locked="false" />
<sodipodi:guide
position="0.79573003,80.992434"
orientation="1,0"
id="guide155"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,49.080852"
orientation="-0.70710678,0.70710678"
id="guide159"
inkscape:locked="false" />
<sodipodi:guide
position="35.815724,49.080852"
orientation="0.70710678,0.70710678"
id="guide161"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,22.622512"
orientation="0,1"
id="guide163"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,31.882933"
orientation="0.70710678,0.70710678"
id="guide165"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,31.882943"
orientation="-0.70710678,0.70710678"
id="guide167"
inkscape:locked="false" />
<sodipodi:guide
position="35.815714,31.882933"
orientation="0,1"
id="guide169"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,34.528763"
orientation="0.70710678,0.70710678"
id="guide171"
inkscape:locked="false" />
<sodipodi:guide
position="35.815734,34.528763"
orientation="-0.70710678,0.70710678"
id="guide173"
inkscape:locked="false" />
<sodipodi:guide
position="9.3573983,37.174603"
orientation="1,0"
id="guide179"
inkscape:locked="false" />
<sodipodi:guide
position="62.274065,49.080852"
orientation="1,0"
id="guide181"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-75.309265,-18.156247)">
<path
style="fill:#c8d129;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 109.80208,23.156247 99.218749,33.739579 V 69.458334 L 109.80209,58.875001 Z"
id="path175"
inkscape:connector-curvature="0" />
<path
style="fill:#d57b28;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 112.44792,23.156247 10.58333,10.583335 V 69.458334 L 112.44792,58.875001 Z"
id="path177"
inkscape:connector-curvature="0" />
<path
style="fill:#009de0;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 97.895829,54.377079 V 39.824995 L 84.666663,53.054162 v 14.552083 z"
id="path183"
inkscape:connector-curvature="0" />
<path
style="fill:#68696b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 84.666666,69.458334 9.260416,-9.260417 h 5.291667 v 9.260417 z"
id="path185"
inkscape:connector-curvature="0" />
<path
style="fill:#68696b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 101.86457,69.458334 9.26043,-9.260425 9.26042,9.260419 z"
id="path187"
inkscape:connector-curvature="0" />
<path
style="fill:#68696b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 137.58333,69.458334 -9.26041,-9.260417 h -5.29167 v 9.260417 z"
id="path189"
inkscape:connector-curvature="0" />
<path
style="fill:#bf2b1b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 124.35417,54.112492 V 39.560411 l 13.22916,13.229167 v 14.552083 z"
id="path191"
inkscape:connector-curvature="0" />
<g
id="g1029"
transform="translate(-1.2138998,-11.055804)">
<text
id="text1000"
y="97.953201"
x="81.170387"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:6.61458302px;font-family:'Baekmuk Headline';-inkscape-font-specification:'Baekmuk Headline, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#868789;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;font-family:'Baekmuk Headline';-inkscape-font-specification:'Baekmuk Headline, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#868789;fill-opacity:1;stroke-width:0.26458332px"
y="97.953201"
x="81.170387"
id="tspan998"
sodipodi:role="line">test</tspan></text>
<text
id="text1023"
y="97.995537"
x="110.84151"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;line-height:6.61458302px;font-family:'Baekmuk Headline';-inkscape-font-specification:'Baekmuk Headline, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#009de0;fill-opacity:1;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:14.11111069px;font-family:'Baekmuk Headline';-inkscape-font-specification:'Baekmuk Headline, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-feature-settings:normal;text-align:start;writing-mode:lr-tb;text-anchor:start;fill:#009de0;fill-opacity:1;stroke-width:0.26458332px"
y="97.995537"
x="110.84151"
id="tspan1021"
sodipodi:role="line">infra</tspan></text>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.7 KiB

BIN
Pepiniere/Pepinière/ansible/images/manual-deployment-without-ansible.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
Pepiniere/Pepinière/ansible/images/tower-dashboard.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
Pepiniere/Pepinière/ansible/images/tp.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

150
Pepiniere/Pepinière/ansible/index.html

@ -0,0 +1,150 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - Ansible</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="1.Introduction-ansible.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="2.installation-inventaire.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="3.commandes-ad-hoc.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="4.playbooks.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="5.roles.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="6.structures-de-controle.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="7.templates.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="8.notions-avancees.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="9.Ansible-Galaxy.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
<section data-markdown="10.bonnes-pratiques.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • février 2019</p>
</body>
</html>

72
Pepiniere/Pepinière/ansible/introduction.html

@ -0,0 +1,72 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>SII - Formation Ansible</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<link rel="stylesheet" href="revealjs/css/custom.css"> <!-- your custom styles -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="0.Introduction-formation.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/lib/js/head.min.js"></script>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
history: true,
// Transition style
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Transition style for full page slide backgrounds
backgroundTransition: 'none', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js' },
{ src: 'revealjs/plugin/markdown/markdown.js' },
{ src: 'revealjs/plugin/notes/notes.js', async: true },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
]
});
// Slide number formatting can be configured using these variables:
// "h.v": horizontal . vertical slide number (default)
// "h/v": horizontal / vertical slide number
// "c": flattened slide number
// "c/t": flattened slide number / total slides
Reveal.configure({ slideNumber: 'c/t' });
Reveal.configure({ transition: 'none' });
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • février 2019</p>
</body>
</html>

28
Pepiniere/Pepinière/ansible/travaux-pratiques/2.tp-deploiement-app.md

@ -0,0 +1,28 @@
# TP 2 : Déploiement d’une application
Opérations à faire :
* Installation des middlewares ( serveur web et serveur bdd)
* Création d’une base de donnée et d’un utilisateur
* Télécharger un wordpress et le déployer au bon endroit et avec les bon droits
* Editer sa configuration pour y adjoindre la base de données
* Tester pour vérifier que tout fonctionne
Détails des actions à faire dans :
```
/home/formation/script-tp2.sh 
```
Conseils :
Utilisation des modules suivants :
* yum
* service
* command
* mysql_db
* mysql_user
* get_url
* unarchive
* copy
* lineinfile

5
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/apache-handlers.yaml

@ -0,0 +1,5 @@
- name: Reload Apache
service:
name: httpd
state: restarted

38
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/apache-install.yaml

@ -0,0 +1,38 @@
- name: Installation of apache package
dnf:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
dnf:
name: php
state: present
update_cache: yes
- name: Installation of php-mysqlnd package
dnf:
name: php-mysqlnd
state: present
update_cache: yes
notify: Reload Apache
- name: Installation of wget package
dnf:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes

19
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/mariadb-install.yaml

@ -0,0 +1,19 @@
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes

20
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/mariadb-wordpress-configure.yaml

@ -0,0 +1,20 @@
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new database user with name '{{ DB_USER }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present

31
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/wordpress-configure.yaml

@ -0,0 +1,31 @@
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'

18
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/imports/wordpress-install.yaml

@ -0,0 +1,18 @@
- name: Download wordpress archive
get_url:
#url: https://wordpress.org/latest.tar.gz
url: https://wordpress.org/wordpress-5.0.8.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar wordpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent

26
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-imports/install-apache-wordpress-mariadb-imports.yaml

@ -0,0 +1,26 @@
- hosts: ansible-2
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
- WEB_HOST: "{{ hostvars['ansible-1']['ansible_ssh_host'] }}"
tasks:
- include_tasks: imports/mariadb-install.yaml
- include_tasks: imports/mariadb-wordpress-configure.yaml
- hosts: ansible-1
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
tasks:
- include_tasks: imports/apache-install.yaml
- include_tasks: imports/wordpress-install.yaml
- include_tasks: imports/wordpress-configure.yaml
handlers:
# On utilise import_tasks pour que le fichier contenant
# les handlers soit chargé dès le départ
- import_tasks: imports/apache-handlers.yaml

18
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/apache-wordpress-mariadb-roles-password.yaml

@ -0,0 +1,18 @@
---
- hosts: centos7
tasks:
- name: Generate random password for DB access
set_fact:
DB_PASSWORD: "{{ lookup('password', 'passwords.txt') }}"
- hosts: ansible-2
roles:
- role: mariadb-install
- role: mariadb-configure
- hosts: ansible-1
roles:
- role: apache-install
- role: wordpress-install
- role: wordpress-configure

5
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/inventories/formation/group_vars/centos7.yaml

@ -0,0 +1,5 @@
---
DB_NAME: wordpress
DB_USER: wordpressuser
DB_HOST: 192.168.56.103
WEB_HOST: 192.168.56.102

17
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/inventories/formation/hosts

@ -0,0 +1,17 @@
ansible-1 ansible_ssh_host=192.168.56.102
ansible-2 ansible_ssh_host=192.168.56.103
ansible-3 ansible_ssh_host=192.168.56.104 tata=tutu
[centos7]
ansible-1
ansible-2
[debian9]
ansible-3
[centos7:vars]
titi=toto
[all:vars]
ansible_become=yes
ansible_become_pass=ansible

1
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/passwords.txt

@ -0,0 +1 @@
f2OLcLega8W,GC6vDiLn

33
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/apache-install/tasks/main.yaml

@ -0,0 +1,33 @@
- name: Installation of apache package
yum:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
yum:
name: php
state: present
update_cache: yes
- name: Installation of php-mysql package
yum:
name: php-mysql
state: present
update_cache: yes
- name: Installation of wget package
yum:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service: name=httpd state=started enabled=yes
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes

19
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/mariadb-configure/tasks/main.yml

@ -0,0 +1,19 @@
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new database user with name '{{ DB_USER }}' and password '{{ DB_PASSWORD }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present

18
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/mariadb-install/tasks/main.yaml

@ -0,0 +1,18 @@
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes

30
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/wordpress-configure/tasks/main.yml

@ -0,0 +1,30 @@
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password '{{ DB_PASSWORD }}'
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'

16
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles-password/roles/wordpress-install/tasks/main.yml

@ -0,0 +1,16 @@
- name: Download worpress archive
get_url:
url: https://wordpress.org/latest.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar worpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent

6
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/inventories/formation/group_vars/wordpress.yaml

@ -0,0 +1,6 @@
---
DB_NAME: wordpress
DB_USER: wordpressuser
DB_PASSWORD: 12345
DB_HOST: "{{ hostvars['ansible-2']['ansible_host'] }}"
WEB_HOST: "{{ hostvars['ansible-1']['ansible_host'] }}"

10
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/inventories/formation/hosts

@ -0,0 +1,10 @@
ansible-1 ansible_host=192.168.56.101
ansible-2 ansible_host=192.168.56.104
[wordpress]
ansible-1
ansible-2
[all:vars]
ansible_become=yes
ansible_become_pass=ansible

9
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/playbook.yaml

@ -0,0 +1,9 @@
---
- hosts: ansible-2
roles:
- role: mariadb
- hosts: ansible-1
roles:
- role: apache
- role: wordpress

36
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/apache/tasks/main.yaml

@ -0,0 +1,36 @@
- name: Installation of apache package
yum:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
yum:
name: php
state: present
update_cache: yes
- name: Installation of php-mysql package
yum:
name: php-mysql
state: present
update_cache: yes
- name: Installation of wget package
yum:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes

4
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/defaults/main.yml

@ -0,0 +1,4 @@
DB_NAME: mydb
DB_USER: bob
DB_PASSWORD: 12345678
WEB_HOST: localhost

19
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/add-database.yml

@ -0,0 +1,19 @@
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new user with name '{{ DB_USER }}' with full access to '{{ DB_NAME }} from '{{ WEB_HOST }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present

18
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/install.yaml

@ -0,0 +1,18 @@
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes

2
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/mariadb/tasks/main.yaml

@ -0,0 +1,2 @@
- import_tasks: install.yaml
- import_tasks: add-database.yaml

3
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/meta/main.yml

@ -0,0 +1,3 @@
---
dependencies:
- role: apache

30
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/configure.yml

@ -0,0 +1,30 @@
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'

16
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/install.yml

@ -0,0 +1,16 @@
- name: Download worpress archive
get_url:
url: https://wordpress.org/latest.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar worpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent

2
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress-roles/roles/wordpress/tasks/main.yaml

@ -0,0 +1,2 @@
- import_tasks: install.yaml
- import_tasks: configure.yaml

6
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/hosts

@ -0,0 +1,6 @@
ansible-1 ansible_ssh_host=192.168.56.106
ansible-2 ansible_ssh_host=192.168.56.107
[all:vars]
ansible_become=yes
ansible_become_pass=ansible

149
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/install-apache-wordpress-mariadb.yaml

@ -0,0 +1,149 @@
---
- hosts: ansible-2
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
- WEB_HOST: "{{ hostvars['ansible-1']['ansible_ssh_host'] }}"
tasks:
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new database user with name '{{ DB_USER }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes
- hosts: ansible-1
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
tasks:
- name: Installation of apache package
dnf:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
dnf:
name: php
state: present
update_cache: yes
- name: Installation of php-mysqlnd package
dnf:
name: php-mysqlnd
state: present
update_cache: yes
notify: Reload Apache
- name: Installation of wget package
dnf:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Download wordpress archive
get_url:
url: https://wordpress.org/wordpress-5.0.8.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar wordpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
handlers:
- name: Reload Apache
service:
name: httpd
state: restarted

53
Pepiniere/Pepinière/ansible/travaux-pratiques/files/tp-wordpress/script-tp2.sh

@ -0,0 +1,53 @@
# --------------------------------------------------------------------------------------------------
# 1/ Installation BDD
# Installation packages Mariadb
yum install mariadb-server
# Mise en place règles firewall
firewall-cmd --add-service=mysql --permanent
firewall-cmd --reload
systemctl enable mariadb
systemctl start mariadb
mysql -u root -p
CREATE DATABASE wordpress;
CREATE USER wordpressuser@localhost IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost;
FLUSH PRIVILEGES;
# --------------------------------------------------------------------------------------------------
# 2/ Installation WEBSERVER
# Installation de Apache
yum install httpd php php-mysql wget
# Mise en place règles firewall
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
systemctl enable httpd
systemctl start httpd
# Configuration de Apache
...
# Déploiement du wordpress :
cd /var/www/html && wget https://wordpress.org/latest.tar.gz
# Décompression du wordpress
tar -xzf /var/www/html/latest.tar.gz -C /var/www/html
rm -f /var/www/html/latest.tar.gz
#create wp config
cp /var/www/html/wordpress/wp-config-sample.php /var/www/html/wordpress/wp-config.php
#set database details
vi /var/www/html/wordpress/wp-config.php
#define('DB_NAME', 'wordpress');
#define('DB_USER', 'wordpressuser');
#define('DB_PASSWORD', 'password');
#define('DB_HOST', 'localhost');

BIN
Pepiniere/Pepinière/ansible/travaux-pratiques/images/ansible-archi-ssh.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

BIN
Pepiniere/Pepinière/ansible/travaux-pratiques/images/ansible-galaxy-search-role.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

1
Pepiniere/Pepinière/ansible/travaux-pratiques/revealjs

@ -0,0 +1 @@
../revealjs

72
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-divers.html

@ -0,0 +1,72 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>SII - TP Ansible : diver</title>
<link rel="icon" type="image/png" href="../revealjs/images/favicon-logo-sii.png" />
<link rel="stylesheet" href="../revealjs/css/reveal.css">
<link rel="stylesheet" href="../revealjs/css/theme/sii.css"> <!-- SII theme -->
<link rel="stylesheet" href="../revealjs/css/custom.css"> <!-- your custom styles -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="../revealjs/lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? '../revealjs/css/print/pdf.css' : '../revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-divers.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="../revealjs/lib/js/head.min.js"></script>
<script src="../revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
history: true,
// Transition style
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Transition style for full page slide backgrounds
backgroundTransition: 'none', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: '../revealjs/plugin/markdown/marked.js' },
{ src: '../revealjs/plugin/markdown/markdown.js' },
{ src: '../revealjs/plugin/notes/notes.js', async: true },
{ src: '../revealjs/plugin/highlight/highlight.js', async: true, callback: function() { hljs.initHighlightingOnLoad(); } }
]
});
// Slide number formatting can be configured using these variables:
// "h.v": horizontal . vertical slide number (default)
// "h/v": horizontal / vertical slide number
// "c": flattened slide number
// "c/t": flattened slide number / total slides
Reveal.configure({ slideNumber: 'c/t' });
Reveal.configure({ transition: 'none' });
</script>
<img class="logo" src="../revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

15
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-divers.md

@ -0,0 +1,15 @@
## TP Complémentaires
* Variabiliser le port d'écoute d'Apache.
* Prévoir de pouvoir dérouler la partie web sur centos _ou_ debian.
* Créer des roles pour installer Docker et Docker-Compose sur Debian
https://docs.docker.com/install/linux/docker-ce/debian/
Vérification :
* $ docker version
* $ docker-compose version

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-galaxy.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible Galaxy</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-galaxy.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • janvier 2019</p>
</body>
</html>

111
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-galaxy.md

@ -0,0 +1,111 @@
## TP Ansible Galaxy
Créer et partager ses propres roles.
## Télécharger des roles
* Aller sur Galaxy https://galaxy.ansible.com et rechercher le role Apache de Geerlingguy.
* Récupérer la CLI d'installation.
![](images/ansible-galaxy-search-role.png)
* Il est également possible de faire une recherche avec la commande `search`
<!-- .slide: data-state="small-code" -->
```none
$ ansible-galaxy search --author geerlingguy apache
Found 14 roles matching your search:
Name Description
---- -----------
geerlingguy.adminer Installs Adminer for Database management.
geerlingguy.apache Apache 2.x for Linux.
geerlingguy.apache-php-fpm Apache 2.4+ PHP-FPM support for Linux.
geerlingguy.certbot Installs and configures Certbot (for Let's Encrypt).
geerlingguy.drupal Deploy or install Drupal on your servers.
geerlingguy.htpasswd htpasswd installation and helper role for Linux serv...
geerlingguy.munin Munin monitoring server for RedHat/CentOS or Debian/...
geerlingguy.php PHP for RedHat/CentOS/Fedora/Debian/Ubuntu.
geerlingguy.pimpmylog Pimp my Log installation for Linux
geerlingguy.solr Apache Solr for Linux.
geerlingguy.supervisor Supervisor (process state manager) for Linux.
geerlingguy.svn SVN web server for Linux
geerlingguy.tomcat6 Tomcat 6 for RHEL/CentOS and Debian/Ubuntu.
geerlingguy.varnish Varnish for Linux.
```
* Installer le role apache récupéré.
<!-- .slide: data-state="small-code" -->
```none
$ ansible-galaxy install geerlingguy.apache
- downloading role 'apache', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-apache/archive/3.0.3.tar.gz
- extracting geerlingguy.apache to /home/formationback/.ansible/roles/geerlingguy.apache
- geerlingguy.apache (3.0.3) was installed successfully
```
* Parcourons ensemble la structure des dossiers et notamment le dossier meta.
<!-- .slide: data-state="small-code" -->
```none
$ cat /home/ansible/.ansible/roles/geerlingguy.apache/meta/main.yml
```
```yaml
dependencies: []
galaxy_info:
author: geerlingguy
description: Apache 2.x for Linux.
company: "Midwestern Mac, LLC"
license: "license (BSD, MIT)"
min_ansible_version: 2.4
platforms:
- name: EL
versions:
- all
- name: Fedora
versions:
- all
- name: Amazon
versions:
- all
- name: Debian
versions:
- all
- name: Ubuntu
versions:
- trusty
- xenial
- bionic
- name: Solaris
versions:
- 11.3
galaxy_tags:
- web
- apache
- webserver
- html
- httpd
allow_duplicates: true
```
## Gérer les roles comme des dépendances externes
* Pour ce TP, nous allons réutiliser les roles que vous venez de créer. Pour plus de facilité, les versions finales sont déjà présentes sur le GitLab `https://gitlab.com/a-berthout`.
* Grâce à Ansible Galaxy, dans votre projet actuel, récupérer les roles suivants :
* Apache sur la branche master
* MariaDB sur la branche develop
* Wordpress sur le tag V1.0.0

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-imports.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les imports</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-imports.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

215
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-imports.md

@ -0,0 +1,215 @@
## TP Imports
* Reprendre le TP Wordpress et découper le Playbook en plusieurs fichiers de tâches.
* Exemples de découpage pouvant être définis :
<small>
- mariadb-install.yaml
- mariadb-configure.yaml
- apache-install.yaml
- apache-configure.yaml
- wordpress-install.yaml
- wordpress-configure.yaml
- test-service.yaml
</small>
* Utiliser `include_tasks` pour charger les fichiers de tâches.
`install-apache-wordpress-mariadb-imports.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- hosts: ansible-2
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
- WEB_HOST: "{{ hostvars['ansible-1']['ansible_ssh_host'] }}"
tasks:
- include_tasks: imports/mariadb-install.yaml
- include_tasks: imports/mariadb-wordpress-configure.yaml
- hosts: ansible-1
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_ssh_host'] }}"
tasks:
- include_tasks: imports/apache-install.yaml
- include_tasks: imports/wordpress-install.yaml
- include_tasks: imports/wordpress-configure.yaml
handlers:
# On utilise import_tasks pour que le fichier contenant
# les handlers soit chargé dès le départ
- import_tasks: imports/apache-handlers.yaml
```
`imports/mariadb-install.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes
```
`imports/mariadb-wordpress-configure.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new database user with name '{{ DB_USER }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present
```
`imports/apache-install.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Installation of apache package
dnf:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
dnf:
name: php
state: present
update_cache: yes
- name: Installation of php-mysqlnd package
dnf:
name: php-mysqlnd
state: present
update_cache: yes
notify: Reload Apache
- name: Installation of wget package
dnf:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
```
`imports/apache-handlers.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Reload Apache
service:
name: httpd
state: restarted
```
`imports/wordpress-install.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Download wordpress archive
get_url:
url: https://wordpress.org/wordpress-5.0.8.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar wordpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent
```
`imports/wordpress-configure.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'
```

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-inventaire.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : Inventaire</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-inventaire.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

268
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-inventaire.md

@ -0,0 +1,268 @@
# TP Ansible
## Les bases
* Préparer les machines cibles.
* Créer un fichier d'inventory.
* Vérifier le bon fonctionnement d'Ansible.
## Vérifier la version de Ansible
```none
ansible@ansible-0:~$ ansible --version
ansible 2.6.4
config file = /etc/ansible/ansible.cfg
configured module search path = [u'/home/ansible/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/dist-packages/ansible
executable location = /usr/bin/ansible
python version = 2.7.13 (default, Nov 24 2017, 17:33:09) [GCC 6.3.0 20170516]
```
## Préparer les machines cibles
Pour que Ansible puisse se connecter à des machines distantes, il faut :
1. Mettre en place une authentification
via une paire de clés ssh,
2. Générer un fichier d'inventaire qui contiendra
la liste des machines.
## Authentification via clés ssh
![Schéma connexion ssh](images/ansible-archi-ssh.png) <!-- .element: height="550px" -->
* Créer une paire de clés ssh
<!-- .slide: data-state="small-code" -->
```none
$ cd
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/ansible/.ssh/id_rsa):
Created directory '/home/ansible/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/ansible/.ssh/id_rsa.
Your public key has been saved in /home/ansible/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:pipIK6HsauJKf2TuyRRWf/EYgUggRknBmtbIuGVq0/g ansible@ansible-0
The key's randomart image is:
+---[RSA 2048]----+
| +*o.o.. .. |
| .o. . . . |
|o = . o |
|.*o. . . = |
|.=o o S. o . |
|+= ..o.o . |
|=++ +.. |
|*+oEo+. |
|@o o++ |
+----[SHA256]-----+
```
<!-- .element: class="fragment" data-fragment-index="1" -->
```none
$ ls -l ~/.ssh/
total 12
-rw------- 1 ansible ansible 1679 sept. 20 09:43 id_rsa
-rw-r--r-- 1 ansible ansible 407 sept. 20 09:43 id_rsa.pub
```
<!-- .element: class="fragment" data-fragment-index="2" -->
* Copier la clé publique sur les machines cibles
```none
$ ssh-copy-id -i 192.168.56.102
$ ssh 192.168.56.102
$ ssh-copy-id -i 192.168.56.103
$ ssh 192.168.56.103
$ ssh-copy-id -i 192.168.56.104
$ ssh 192.168.56.104
```
<!-- .element: class="fragment" data-fragment-index="1" -->
## Fichier d'inventaire minimal
* Créer le fichier d'inventaire
`inventories/formation/hosts`.
```none
$ mkdir -p inventories/formation
$ cat <<EOF > inventories/formation/hosts
192.168.56.102
192.168.56.103
192.168.56.104
EOF
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Vérifier l'inventaire.
```none
$ ansible all --list-hosts
[WARNING]: provided hosts list is empty,
only localhost is available.
Note that the implicit localhost does not match 'all'
hosts (0):
```
```none
$ ansible all -i inventories/formation/hosts --list-hosts
hosts (3):
192.168.56.102
192.168.56.103
192.168.56.104
```
<!-- .element: class="fragment" data-fragment-index="1" -->
Syntaxe des commandes :
`ansible <host-pattern> [options]`
* Tester le ping via Ansible.
```none
$ ansible all -i inventories/formation/hosts -m ping
192.168.56.104 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.56.103 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.56.102 | SUCCESS => {
"changed": false,
"ping": "pong"
}
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Ajouter le nom des machines dans l'inventaire
via la syntaxe :
`<host-name> ansible_host=<ip-address>`
```none
$ cat inventories/formation/hosts
ansible-1 ansible_host=192.168.56.102
ansible-2 ansible_host=192.168.56.103
ansible-3 ansible_host=192.168.56.104
```
<!-- .element: class="fragment" data-fragment-index="1" -->
```none
$ ansible all -i inventories/formation/hosts --list-hosts
hosts (3):
ansible-1
ansible-2
ansible-3
```
<!-- .element: class="fragment" data-fragment-index="2" -->
* Tester de nouveau le ping et vérifier que les hostnames apparaissent maintenant dans les résultats.
```none
$ ansible all -i inventories/formation/hosts -m ping
ansible-3 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Regrouper les machines en 2 groupes :
`centos` et `debian`.
```none
$ cat inventories/formation/hosts
ansible-1 ansible_host=192.168.56.102
ansible-2 ansible_host=192.168.56.103
ansible-3 ansible_host=192.168.56.104
[centos]
ansible-1
ansible-2
[debian]
ansible-3
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Tester de nouveau le ping mais cette fois-ci uniquement sur les machines CentOS.
```none
$ ansible centos -i inventories/formation/hosts -m ping
ansible-2 | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible-1 | SUCCESS => {
"changed": false,
"ping": "pong"
}
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Créer un groupe `tous` qui regroupera
les groupes `centos` et `debian`.
* Tester de nouveau le ping sur le groupe `tous`.
```none
ansible-1 ansible_host=192.168.56.102
ansible-2 ansible_host=192.168.56.103
ansible-3 ansible_host=192.168.56.104
[centos]
ansible-1
ansible-2
[debian]
ansible-3
[tous:children]
centos
debian
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Créer un snapshot Virtualbox pour les machines
- ansible-1
- ansible-2
- ansible-3

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-les-commandes-ad-hoc.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les commandes ad-hoc</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-les-commandes-ad-hoc.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

287
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-les-commandes-ad-hoc.md

@ -0,0 +1,287 @@
# TP Ansible
## Les commandes ad-hoc
Exécuter rapidement des commandes simples.
## Execution de commandes à l'aide de modules
<small>`$ ansible <host-pattern> -m <module> [-a <params>]`</small>
* <small>`-m` nom du module</small>
* <small>`-a <params>` paramètres du module (optionnel)</small>
* Exécuter sur toutes les machines la commande `uname -a` via le module `command`.
<!-- .slide: data-state="medium-code" -->
```none
$ ansible all -i inventories/formation/hosts -m command -a "uname -a"
ansible-3 | SUCCESS | rc=0 >>
Linux ansible-3 4.9.0-8-amd64 #1 SMP Debian
4.9.110-3+deb9u4 (2018-08-21) x86_64 GNU/Linux
ansible-2 | SUCCESS | rc=0 >>
Linux ansible-2 3.10.0-862.11.6.el7.x86_64 #1
SMP Tue Aug 14 21:49:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
ansible-1 | SUCCESS | rc=0 >>
Linux ansible-1 3.10.0-862.11.6.el7.x86_64 #1
SMP Tue Aug 14 21:49:04 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Copier le fichier `/etc/passwd` de la machine maître à l'emplacement `~/passwd` sur les machines `centos` en utilisant le module `copy`.
* Vérifier la présence du fichier à l'aide du module `command`.
* Copie du fichier :
<!-- .slide: data-state="small-code" -->
```none
$ ansible centos -i inventories/formation/hosts -m copy \
-a "src=/etc/passwd dest=~/passwd"
ansible-2 | SUCCESS => {
"changed": true,
"checksum": "1e9317514c0769f49ec9439f9811675ac19d89ee",
"dest": "/home/ansible/passwd",
"gid": 1001,
"group": "ansible",
"md5sum": "b8bbe17a63c7bb500c89dc5e29351fc5",
"mode": "0664",
"owner": "ansible",
"size": 1574,
"src": "/home/ansible/.ansible/tmp/ansible-tmp-1537539186.68-18012403191...",
"state": "file",
"uid": 1001
}
ansible-1 | SUCCESS => {
"changed": true,
"checksum": "1e9317514c0769f49ec9439f9811675ac19d89ee",
"dest": "/home/ansible/passwd",
"gid": 1001,
"group": "ansible",
"md5sum": "b8bbe17a63c7bb500c89dc5e29351fc5",
"mode": "0664",
"owner": "ansible",
"size": 1574,
"src": "/home/ansible/.ansible/tmp/ansible-tmp-1537539186.66-20188089735...",
"state": "file",
"uid": 1001
}
```
* Vérification à l'aide du module `command` :
<!-- .slide: data-state="medium-code" -->
```none
$ ansible centos7 -i inventories/formation/hosts -m command \
-a "ls -l ~"
ansible-2 | SUCCESS | rc=0 >>
total 4
-rw-rw-r-- 1 ansible ansible 1574 21 sept. 16:13 passwd
ansible-1 | SUCCESS | rc=0 >>
total 4
-rw-rw-r-- 1 ansible ansible 1574 21 sept. 16:13 passwd
```
## Variables dans l'inventaire
<!-- .slide: data-state="medium-code" -->
`inventories/formation/hosts`
```ini
$ cat inventories/formation/hosts
ansible-1 ansible_host=192.168.56.102
ansible-2 ansible_host=192.168.56.103
ansible-3 ansible_host=192.168.56.104 tata=tutu # variable
# de machine
[centos7]
ansible-1
ansible-2
[debian9]
ansible-3
[centos7:vars] # variable
titi=toto # de groupe
[all:vars]
ansible_become=yes
ansible_become_pass=ansible
```
<!-- .slide: data-state="small-code" -->
```yaml
$ ansible-inventory -i inventories/formation/hosts --list --yaml
all:
children:
centos7:
hosts:
ansible-1:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.102
titi: toto
ansible-2:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.103
titi: toto
debian9:
hosts:
ansible-3:
ansible_become: 'yes'
ansible_become_pass: ansible
ansible_host: 192.168.56.104
tata: tutu
ungrouped: {}
```
## Obtenir les droits root
* Essayer de créer sur chaque machine un fichier dans le homedir de l'utilisateur `root`.
<!-- .slide: data-state="small-code" -->
```none
$ ansible all -i inventories/formation/hosts -m command -a "touch /root/pas-le-droit"
ansible-3 | FAILED | rc=1 >>
touch: impossible de faire un touch '/root/pas-le-droit':
Permission non accordéenon-zero return code
ansible-2 | FAILED | rc=1 >>
touch: impossible de faire un touch « /root/pas-le-droit »:
Permission non accordéenon-zero return code
ansible-1 | FAILED | rc=1 >>
touch: impossible de faire un touch « /root/pas-le-droit »:
Permission non accordéenon-zero return code
```
<!-- .element: class="fragment" data-fragment-index="1" -->
<!-- .slide: data-state="medium-code" -->
* Ajouter des variables `ansible_become` dans l'inventaire pour permettre l'exécution via `sudo` ou `su`.
```none
...
# Par défaut sudo est utilisé, il faut donc que
# l'utilisateur soit déclaré dans les sudoers
[all:vars]
ansible_become=yes
ansible_become_pass=ansible
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Essayer de nouveau de créer sur chaque machine un fichier dans le homedir de l'utilisateur `root`.
* Vérifier la bonne création du fichier à l'aide de la commande `ls`.
<!-- .slide: data-state="small-code" -->
```none
$ ansible all -i inventories/formation/hosts -m command -a "touch /root/fichier"
ansible-3 | SUCCESS | rc=0 >>
ansible-2 | SUCCESS | rc=0 >>
ansible-1 | SUCCESS | rc=0 >>
```
<!-- .element: class="fragment" data-fragment-index="1" -->
```none
$ ansible all -i inventories/formation/hosts -m command -a "ls -l /root/fichier"
ansible-3 | SUCCESS | rc=0 >>
-rw-r--r-- 1 root root 0 sept. 20 16:20 /root/fichier
ansible-2 | SUCCESS | rc=0 >>
-rw-r--r-- 1 root root 0 20 sept. 16:20 /root/fichier
ansible-1 | SUCCESS | rc=0 >>
-rw-r--r-- 1 root root 0 20 sept. 16:20 /root/fichier
```
<!-- .element: class="fragment" data-fragment-index="2" -->
## Récupérer des informations sur les machines
* Utiliser le module `setup` pour lister les "facts" de chaque machine.
<!-- .slide: data-state="medium-code" -->
```none
$ ansible all -i inventories/formation/hosts -m setup
ansible-3 | SUCCESS => {
"ansible_facts": {
"ansible_all_ipv4_addresses": [
"10.0.2.15",
"192.168.56.5"
],
"ansible_all_ipv6_addresses": [
"fe80::a00:27ff:fe51:f40c",
"fe80::a00:27ff:fe38:cf21"
],
"ansible_apparmor": {
"status": "disabled"
},
"ansible_architecture": "x86_64",
"ansible_bios_date": "12/01/2006",
"ansible_bios_version": "VirtualBox",
"ansible_cmdline": {
"BOOT_IMAGE": "/boot/vmlinuz-4.9.0-8-amd64",
```
<!-- .element: class="fragment" data-fragment-index="2" -->
* Appliquer un filtre pour n'afficher que
les adresses IP v4 de chaque machine
en ajoutant l'option `-a 'filter=<field>'`.
<!-- .slide: data-state="medium-code" -->
```none
$ ansible all -i inventories/formation/hosts -m setup \
-a 'filter=ansible_all_ipv4_addresses' --one-line
ansible-3 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses":
["10.0.2.15", "192.168.56.104"]}, "changed": false}
ansible-2 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses":
["192.168.56.103", "10.0.2.15"]}, "changed": false}
ansible-1 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses":
["192.168.56.102", "10.0.2.15"]}, "changed": false}
```
<!-- .element: class="fragment" data-fragment-index="1" -->
* Appliquer un filtre pour n'afficher que la famille d'OS.
<!-- .slide: data-state="medium-code" -->
```none
$ ansible all -i inventories/formation/hosts -m setup \
-a 'filter=ansible_os_family' --one-line
ansible-3 | SUCCESS => {"ansible_facts": {"ansible_os_family":
"Debian"}, "changed": false}
ansible-1 | SUCCESS => {"ansible_facts": {"ansible_os_family":
"RedHat"}, "changed": false}
ansible-2 | SUCCESS => {"ansible_facts": {"ansible_os_family":
"RedHat"}, "changed": false}
```
<!-- .element: class="fragment" data-fragment-index="1" -->

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-playbooks.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les playbooks</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-playbooks.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

434
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-playbooks.md

@ -0,0 +1,434 @@
# TP Ansible
## Les Playbooks
Créer un Playbook et l'exécuter sur des cibles.
* Créer dans le dossier de travail un fichier playbook nommé `get-user-id.yaml` avec le contenu suivant :
```yaml
- hosts: all
tasks:
- name: Get user id
command: id
```
* Que va faire ce playbook ?
* Exécuter le Playbook :
<!-- .slide: data-state="small-code" -->
```nohighlight
$ ansible-playbook -i inventories/formation/hosts playbooks/get-user-id.yaml
PLAY [all] ********************************************************************
TASK [Gathering Facts] ********************************************************
ok: [ansible-3]
ok: [ansible-2]
ok: [ansible-1]
TASK [Get user id] ************************************************************
changed: [ansible-3]
changed: [ansible-2]
changed: [ansible-1]
PLAY RECAP ********************************************************************
ansible-1 : ok=2 changed=1 unreachable=0 failed=0
ansible-2 : ok=2 changed=1 unreachable=0 failed=0
ansible-3 : ok=2 changed=1 unreachable=0 failed=0
```
L'action est bien effectuée même si on ne voit pas le détail.
* Relancer l'éxécution du Playbook en mode verbeux.
<!-- .slide: data-state="small-code" -->
```nohighlight
$ ansible-playbook -v -i inventories/formation/hosts playbooks/get-user-id.yaml
PLAY [all] ********************************************************************
TASK [Gathering Facts] ********************************************************
ok: [ansible-3]
ok: [ansible-2]
ok: [ansible-1]
TASK [Get user id] ************************************************************
changed: [ansible-3] => {"changed": true, "cmd": ["id"], "delta": "0:00:00.008768", "end": "2018-09-21 17:06:07.020080", "rc": 0, "start": "2018-09-21 17:06:07.011312", "stderr": "", "stderr_lines": [], "stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),27(sudo)", "stdout_lines": ["uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),27(sudo)"]}
changed: [ansible-2] => {"changed": true, "cmd": ["id"], "delta": "0:00:00.010668", "end": "2018-09-21 17:06:02.736220", "rc": 0, "start": "2018-09-21 17:06:02.725552", "stderr": "", "stderr_lines": [], "stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),10(wheel)", "stdout_lines": ["uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),10(wheel)"]}
changed: [ansible-1] => {"changed": true, "cmd": ["id"], "delta": "0:00:00.008940", "end": "2018-09-21 17:06:06.974383", "rc": 0, "start": "2018-09-21 17:06:06.965443", "stderr": "", "stderr_lines": [], "stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),10(wheel)", "stdout_lines": ["uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),10(wheel)"]}
PLAY RECAP ********************************************************************
ansible-1 : ok=2 changed=1 unreachable=0 failed=0
ansible-2 : ok=2 changed=1 unreachable=0 failed=0
ansible-3 : ok=2 changed=1 unreachable=0 failed=0
```
Pas très pratique...
* Utiliser le paramètre `register` pour enregistrer le résultat de la commande.
* Créer une nouvelle tâche basée sur le module `debug` pour afficher le résultat de la commande.
https://docs.ansible.com/ansible/latest/modules/debug_module.html
`playbooks/get-user-id.yaml`
```yaml
- hosts: all
tasks:
- name: Get user id
command: id
register: user_id
- name: Display user id
debug:
var: user_id.stdout
```
<!-- .slide: data-state="small-code" -->
```nohighlight
$ ansible-playbook -i inventories/formation/hosts playbooks/get-user-id.yaml
...
TASK [Get user id] ************************************************************
changed: [ansible-3]
changed: [ansible-2]
changed: [ansible-1]
TASK [Display user id] ********************************************************
ok: [ansible-1] => {
"user_id.stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),
10(wheel)"
}
ok: [ansible-2] => {
"user_id.stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),
10(wheel)"
}
ok: [ansible-3] => {
"user_id.stdout": "uid=1001(ansible) gid=1001(ansible) groupes=1001(ansible),
27(sudo)"
}
PLAY RECAP ********************************************************************
ansible-1 : ok=3 changed=1 unreachable=0 failed=0
ansible-2 : ok=3 changed=1 unreachable=0 failed=0
ansible-3 : ok=3 changed=1 unreachable=0 failed=0
```
## TP Installer Apache httpd
Installation d'un serveur web Apache httpd.
* Créer un playbook qui exécutera les tâches suivantes sur la machine `ansible-1` :
- Installe le paquet `httpd` et lancer le service `httpd`,
- Configure le service `httpd` pour qu'il se relance à chaque redémarrage du système,
- Créé et copie une page web statique à l'emplacement `/var/www/html/index.html`,
- Configure firewalld pour autoriser le traffic `http` entrant,
* Exécuter le Playbook sur la cible
`ansible-1`.
* Se connecter à l'application dans
le navigateur web.
```yaml
- hosts: ansible-1
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
- name: Copying homepage
copy:
src: index.html
dest: /var/www/html/index.html
mode: 0444
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
```
## TP Installer un Wordpress
Installation de l'outil de blog Wordpress.
* Serveur de base de données : `ansible-2` (centos 7)
* Installer le serveur Mariadb <small>(mariadb-server)</small>
* Créer une base de donnée et un utilisateur <small>(modules mysql_db, mysql_user)</small>
---
* Serveur web : `ansible-1` (centos 8)
* Installer le serveur Apache httpd + php <small>(httpd, php, php-mysqlnd)</small>
* Télécharger Wordpress _5.0.8_ <small>(https://wordpress.org/wordpress-5.0.8.tar.gz)</small>
* Décompresser le dossier dans _/var/www/html/_ avec les bon droits <small>(module unarchive)</small>
* Editer la configuration de Wordpress pour qu'il accède à la bdd
### 1. Base de données
* Installer le serveur Mariadb
* Créer une base de donnée et un utilisateur
<!-- .slide: data-state="medium-code" -->
```bash
# Installation packages Mariadb
yum install mariadb-server
# Mise en place règles firewall
firewall-cmd --add-service=mysql --permanent
firewall-cmd --reload
# Options de démarrage de Mariadb
systemctl enable mariadb
systemctl start mariadb
# Création base et utilisateur
mysql -u root -p
CREATE DATABASE wordpress;
CREATE USER wordpressuser@localhost IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON wordpress.* TO wordpressuser@localhost;
FLUSH PRIVILEGES;
```
### 2. Apache
<!-- .slide: data-state="medium-code" -->
```bash
# Installation de Apache
yum install httpd php php-mysql wget
# Mise en place règles firewall
firewall-cmd --add-service=http --permanent
firewall-cmd --reload
# Options de démarrage de Apache
systemctl enable httpd
systemctl start httpd
```
### 3. Wordpress
<!-- .slide: data-state="medium-code" -->
```bash
# Déploiement de wordpress :
cd /var/www/html && wget https://wordpress.org/latest.tar.gz
# Décompression de wordpress
tar -xzf /var/www/html/latest.tar.gz -C /var/www/html
rm -f /var/www/html/latest.tar.gz
# Configuration de Wordpress
cp /var/www/html/wordpress/wp-config-sample.php \
/var/www/html/wordpress/wp-config.php
vi /var/www/html/wordpress/wp-config.php
# define('DB_NAME', 'wordpress');
# define('DB_USER', 'wordpressuser');
# define('DB_PASSWORD', 'password');
# define('DB_HOST', 'localhost');
```
Quelques modules possibles...
* yum
* service
* command
* mysql_db
* mysql_user
* file
* get_url
* unarchive
* copy
* lineinfile
* replace
<!-- .slide: data-state="medium-code" -->
`install-apache-wordpress-mariadb.yaml`
```yaml
- hosts: ansible-2
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_host'] }}"
- WEB_HOST: "{{ hostvars['ansible-1']['ansible_host'] }}"
tasks:
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new database user with name '{{ DB_USER }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes
- hosts: ansible-1
vars:
- DB_NAME: wordpress
- DB_USER: wordpressuser
- DB_PASSWORD: "12345"
- DB_HOST: "{{ hostvars['ansible-2']['ansible_host'] }}"
tasks:
- name: Installation of apache package
dnf:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
dnf:
name: php
state: present
update_cache: yes
- name: Installation of php-mysqlnd package
dnf:
name: php-mysqlnd
state: present
update_cache: yes
notify: Reload Apache
- name: Installation of wget package
dnf:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Download worpress archive
get_url:
url: https://wordpress.org/wordpress-5.0.8.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar worpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
handlers:
- name: Reload Apache
service:
name: httpd
state: restarted
```

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-roles.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les roles</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-roles.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

345
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-roles.md

@ -0,0 +1,345 @@
## TP Roles
* Reprendre le TP Wordpress et le découper en Roles.
* Exemple de rôles pouvant être définis :
<small>mariadb, db, httpd, apache, wordpress...</small>
* Gérer les variables par défaut.
* Gérer les variables liées à l'environnement.
* Gérer la dépendances de roles entre l'applicatif et le serveur web.
Arborescence du projet :
<!-- .slide: data-state="small-code" -->
```none
ansible
├── playbook.yaml
├── inventories
   └── formation
   ├── group_vars
     └── wordpress.yaml <--- vars mariadb, wordpress
   └── hosts
└── roles
├── apache
   ├── handlers
     └── main.yaml
   └── tasks
   └── main.yaml
├── mariadb
   ├── defaults
     └── main.yaml <--- vars par défaut mariadb
   └── tasks
   ├── add-database.yaml
   ├── install.yaml
   └── main.yaml
└── wordpress
├── meta
| └── main.yaml <--- dépendances de wordpress
└── tasks
├── configure.yaml
├── install.yaml
└── main.yaml
```
`inventories/formation/hosts`
```ini
ansible-1 ansible_host=192.168.56.102
ansible-2 ansible_host=192.168.56.103
[wordpress]
ansible-1
ansible-2
[all:vars]
ansible_become=yes
ansible_become_pass=ansible
```
`inventories/formation/group_vars/wordpress.yaml`
```yaml
DB_NAME: wordpress
DB_USER: wordpressuser
DB_PASSWORD: "12345"
DB_HOST: "{{ hostvars['ansible-2']['ansible_host'] }}"
WEB_HOST: "{{ hostvars['ansible-1']['ansible_host'] }}"
```
`playbook.yaml`
```yaml
- hosts: ansible-2
roles:
- role: mariadb
- hosts: ansible-1
roles:
- role: apache
- role: wordpress
```
### Role Mariadb
```none
roles
└── mariadb
   ├── defaults
     └── main.yaml
   └── tasks
   ├── add-database.yaml
   ├── install.yaml
   └── main.yaml
```
<!-- .slide: data-state="medium-code" -->
`roles/mariadb/tasks/install.yaml`
```yaml
- name: Installation of mariadb-server package
yum:
name: mariadb-server
state: present
update_cache: yes
- name: Ensure mariadb-server is running (and enabled at boot)
service:
name: mariadb
state: started
enabled: yes
- name: Allow mariadb traffic on port 3306
firewalld:
service: mysql
permanent: true
state: enabled
immediate: yes
```
<!-- .slide: data-state="medium-code" -->
`roles/mariadb/tasks/add-database.yaml`
```yaml
- name: Installation of MySQL-python package
# package required to use ansible mysql modules
yum:
name: MySQL-python
state: present
update_cache: yes
- name: Create a new database with name '{{ DB_NAME }}'
mysql_db:
name: '{{ DB_NAME }}'
state: present
- name: Create a new user with name '{{ DB_USER }}'
with full access to '{{ DB_NAME }} from '{{ WEB_HOST }}'
mysql_user:
name: '{{ DB_USER }}'
password: '{{ DB_PASSWORD }}'
priv: '{{ DB_NAME }}.*:ALL'
host: '{{ WEB_HOST }}'
state: present
```
<!-- .slide: data-state="medium-code" -->
`roles/mariadb/tasks/main.yaml`
```yaml
- import_tasks: install.yaml
- import_tasks: add-database.yaml
```
`roles/mariadb/defaults/main.yaml`
```yaml
DB_NAME: bob
DB_USER: mydb
DB_PASSWORD: 12345678
WEB_HOST: localhost
```
Les valeurs par défaut du role.
### Role Apache
```none
roles
└── apache
   ├── handlers
     └── main.yaml
   └── tasks
   └── main.yaml
```
<!-- .slide: data-state="medium-code" -->
`roles/apache/tasks/main.yaml`
```yaml
- name: Installation of apache package
yum:
name: httpd
state: present
update_cache: yes
- name: Installation of php package
yum:
name: php
state: present
update_cache: yes
- name: Installation of php-mysql package
yum:
name: php-mysql
state: present
update_cache: yes
- name: Installation of wget package
yum:
name: wget
state: present
update_cache: yes
- name: Ensure apache is running (and enabled at boot)
service:
name: httpd
state: started
enabled: yes
- name: Allow http traffic on port 80
firewalld:
service: http
permanent: true
state: enabled
immediate: yes
```
### Role Wordpress
```none
roles
└── wordpress
└── tasks
├── configure.yaml
├── install.yaml
└── main.yaml
```
<!-- .slide: data-state="medium-code" -->
`roles/wordpress/tasks/install.yaml`
```yaml
- name: Download wordpress archive
get_url:
url: https://wordpress.org/latest.tar.gz
dest: /var/www/html/wordpress.tar.gz
mode: 0440
- name: Untar wordpress archive
unarchive:
src: /var/www/html/wordpress.tar.gz
dest: /var/www/html
remote_src: true
- name: Remove wordpress archive
file:
path: /var/www/html/wordpress.tar.gz
state: absent
```
<!-- .slide: data-state="medium-code" -->
`roles/wordpress/tasks/configure.yaml`
```yaml
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file with db name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'database_name_here'
replace: '{{ DB_NAME }}'
- name: Update wordpress configuration file with user name
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'username_here'
replace: '{{ DB_USER }}'
- name: Update wordpress configuration file with user password
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'password_here'
replace: '{{ DB_PASSWORD }}'
- name: Update wordpress configuration file with host
replace:
dest: /var/www/html/wordpress/wp-config.php
regexp: 'localhost'
replace: '{{ DB_HOST }}'
```
<!-- .slide: data-state="medium-code" -->
`roles/wordpress/tasks/main.yaml`
```yaml
- import_tasks: install.yaml
- import_tasks: configure.yaml
```
<!-- .slide: data-state="medium-code" -->
* Générer un mot de passe aléatoirement pour l'accès à la base de données.
* Exemple :
```yaml
tasks:
- name: Generate random password
set_fact:
password: "{{ lookup('password', 'password.txt') }}"
- debug:
msg: "Randomly generated password is : {{ password }}"
```
`apache-wordpress-mariadb-roles-password.yaml`
<!-- .slide: data-state="medium-code" -->
```yaml
- hosts: centos7
tasks:
- name: Generate random password for DB access
set_fact:
DB_PASSWORD: "{{ lookup('password', 'passwords.txt') }}"
- hosts: ansible-2
roles:
- role: mariadb-install
- role: mariadb-configure
- hosts: ansible-1
roles:
- role: apache-install
- role: wordpress-install
- role: wordpress-configure
```
```none
$ ls -l passwords.txt
-rw------- 1 ansible ansible 21 oct. 29 16:48 passwords.txt
```
```none
$ cat passwords.txt
f2OLcLega8W,GC6vDiLn
```

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-structures-de-controle.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les structures de controle</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-structures-de-controle.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

55
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-structures-de-controle.md

@ -0,0 +1,55 @@
## TP Structures de contrôle
Utiliser les boucles pour :
1. gérer l'installation des packages,
2. effectuer les modifications sur le fichier de configuration de Wordpress.
Installation des packages avec `loop`
```yaml
- name: Install packages
yum:
name: "{{ item }}"
state: present
loop:
- php
- php-mysql
- httpd
```
Ou en passant une liste au module `yum`
```yaml
- name: Install packages
yum:
name:
- php
- php-mysql
- httpd
state: present
```
Configuration de Wordpress avec `loop`
<!-- .slide: data-state="medium-code" -->
```yaml
- name: Create wordpress configuration file
copy:
src: /var/www/html/wordpress/wp-config-sample.php
dest: /var/www/html/wordpress/wp-config.php
remote_src: true
- name: Update wordpress configuration file
replace:
path: /var/www/html/wordpress/wp-config.php
regexp: "{{ item.regexp }}"
replace: "{{ item.replace }}"
loop:
- { regexp: 'database_name_here', replace: '{{ DB_NAME }}'}
- { regexp: 'username_here', replace: '{{ DB_USER }}'}
- { regexp: 'password_here', replace: '{{ DB_PASSWORD }}'}
- { regexp: 'localhost', replace: '{{ DB_HOST }}'}
```

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-templates.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible : les templates</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-templates.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • octobre 2018</p>
</body>
</html>

36
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-templates.md

@ -0,0 +1,36 @@
## TP Structures de contrôle
Utiliser un fichier template pour effectuer la configuration de Wordpress.
`templates/wp-config.php.j2`
```php
<?php
...
define('DB_NAME', '{{ dbname }}');
define('DB_USER', '{{ dbuser }}');
define('DB_PASSWORD', '{{ dbpassword }}');
define('DB_HOST', '{{ dbhost }}');
...
```
<!-- .slide: data-state="medium-code" -->
```yaml
- hosts: web
vars:
dbname: wordpress
dbuser: wordpressuser
dbpassword: wpassword
dbhost: localhost
tasks:
- name: Deploy wordpress config
template:
src: templates/wp-config.php.j2
dest: /var/www/html/wordpress/wp-config.php
owner: apache
group: apache
mode: 0600
```
Les variables sont automatiquement injectées dans le fichier sur la cible.

96
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-vault.html

@ -0,0 +1,96 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>SII - TP Ansible Vault</title>
<link rel="icon" type="image/png" href="revealjs/images/favicon-logo-sii.png" />
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="revealjs/css/reset.css">
<link rel="stylesheet" href="revealjs/css/reveal.css">
<link rel="stylesheet" href="revealjs/css/theme/sii.css"> <!-- SII theme -->
<!-- Theme used for syntax highlighting of code -->
<link rel="stylesheet" href="revealjs/lib/css/monokai.css">
<!-- Specific CSS override to reduce font size and align text on the left -->
<style>
.reveal .slides {
text-align: left;
}
.columns {
display: flex;
}
.columns pre {
margin-right: 0.5rem;
}
</style>
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'revealjs/css/print/pdf.css' : 'revealjs/css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<div class="slides">
<section data-markdown="tp-ansible-vault.md"
data-separator="^\n\n\n"
data-separator-vertical="^\n\n"
data-separator-notes="^Note:"
data-charset="UTF-8">
</section>
</div>
</div>
<script src="revealjs/js/reveal.js"></script>
<script>
// More info https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
center: true,
hash: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// More info https://github.com/hakimel/reveal.js#dependencies
dependencies: [
{ src: 'revealjs/plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'revealjs/plugin/highlight/highlight.js', async: true },
{ src: 'revealjs/plugin/search/search.js', async: true },
{ src: 'revealjs/plugin/zoom-js/zoom.js', async: true },
{ src: 'revealjs/plugin/notes/notes.js', async: true }
]
});
Reveal.configure({
slideNumber: 'c/t'
});
</script>
<img class="logo" src="revealjs/images/logo-sii.svg" />
<p class="footer">SII • www.groupe-sii.com • janvier 2019</p>
</body>
</html>

283
Pepiniere/Pepinière/ansible/travaux-pratiques/tp-ansible-vault.md

@ -0,0 +1,283 @@
## TP Ansible Vault
Sécuriser les informations sensibles.
* Créer un dossier nommé `all` dans `group_vars`.
```none
.
└── inventories
   └── formation
   ├── group_vars
     └── all <---- ici
   └── hosts
```
* Créer avec la commande `ansible-vault create` :
- un fichier nommé `vault`
- dans `group_vars/all`.
* Ajouter une variable dans le fichier.
```none
.
└── inventories
   └── formation
   ├── group_vars
     └── all
     └── vault <---- ici
   └── hosts
```
```none
vault_robert_password: Mon super password !
```
* Vérifier le contenu du fichier vault
- avec la commande `cat`,
- avec la commande `ansible-vault view`.
* Il est possible de modifier le contenu du fichier chiffré avec la commande `ansible-vault edit`.
<!-- .slide: data-background="#2E2E2E" data-state="small-code" -->
Avec `cat`
```none
$ cat inventories/formation/group_vars/all/vault
$ANSIBLE_VAULT;1.1;AES256
64373435616463653634613737613565626662326539376138393733333762343364303961306536
6337336233323932346134313838666538363863376562360a326561356365626462373963636233
63613139383437303262616366623538613761336361626665653631343061326535373363643039
3633363965363237370a623063343839626634633435373834386332313933643661356266653265
35333234643234376266343935303837373561333265653338323235656638316539646137313234
3861623031393635646363343662366161343130653864336331
```
Avec `ansible-vault`
```none
$ ansible-vault view inventories/formation/group_vars/all/vault
Vault password:
vault_robert_password: Mon super password !
```
* Créer un playbook nommé `playbook-vault.yaml`.
* Ajouter une tâche de debug qui affichera la variable stockée dans le fichier `vault`.
* Lancer le playbook !
* La structure du dossier de travail est :
```none
.
├── inventories
   └── formation
   ├── group_vars
     └── all
     └── vault
   └── hosts
└── playbook-vault.yaml
```
<!-- .slide: data-background="#2E2E2E" data-state="medium-code" -->
Créer `playbook-vault.yaml`
```yaml
- hosts: debian9
tasks:
- name: Display secured password
debug:
msg: "Robert's password is: {{ vault_robert_password }}"
```
<!-- .slide: data-background="#2E2E2E" data-state="medium-code" -->
Lancer le playbook
```none
$ ansible-playbook -i inventories/formation/hosts playbook-vault.yaml
PLAY [debian9] *****************************************************
ERROR! Attempting to decrypt but no vault secrets found
```
<small>Il nous faut donc préciser le mot de passe de déchiffrement vault en utilisant au choix
l'option `--ask-vault-pass` ou l'option `--vault-password-file`.</small>
<!-- .slide: data-background="#2E2E2E" data-state="small-code" -->
Lancer le playbook avec `--ask-vault-pass`
```none
$ ansible-playbook -i inventories/formation/hosts playbook-vault.yaml --ask-vault-pass
Vault password:
PLAY [debian9] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-3]
TASK [Display secured password] ************************************************
ok: [ansible-3] => {
"msg": "Robert's password is: Mon super password !"
}
PLAY RECAP *********************************************************************
ansible-3 : ok=2 changed=0 unreachable=0 failed=0
```
* Afin d'éviter d'avoir à taper le mot de passe vault à chaque fois, mettons le dans un fichier !
* Relancer le playbook en précisant l'option
`--vault-password-file`.
<!-- .slide: data-background="#2E2E2E"" -->
Créer un fichier contenant le mot de passe vault
```none
$ echo "12345678" > vault-password
$ chmod 600 vault-password
```
<small>`Attention` ! Dans un environnement Git attention à ne pas versionner le fichier contenant le mot de passe, en utilisant `.gitignore` par exemple.</small>
<!-- .slide: data-background="#2E2E2E" data-state="small-code" -->
Relancer le playbook avec l'option
`--vault-password-file`
```none
$ ansible-playbook -i inventories/formation/hosts playbook-vault.yaml \
--vault-password-file vault-password
PLAY [debian9] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-3]
TASK [Display secured password] ************************************************
ok: [ansible-3] => {
"msg": "Robert's password is: Mon super password !"
}
PLAY RECAP *********************************************************************
ansible-3 : ok=2 changed=0 unreachable=0 failed=0
```
* Pour éviter d'avoir à préciser le fichier de mot de passe vault à chaque exécution du playbook, il est possible d'en préciser le nom une fois pour toutes dans le fichier de configuration `ansible.cfg` à la racine du projet local.
* Créer le fichier `ansible.cfg` et ajouter le paramètre `vault_password_file` dans la section `[defaults]`.
* La structure du dossier de travail devient :
```none
.
├── ansible.cfg <----- c'est ici que ça se passe
├── inventories
   └── formation
   ├── group_vars
     └── all
     ├── vars
     └── vault
   └── hosts
├── playbook-vault.yaml
└── vault-password
```
<!-- .slide: data-background="#2E2E2E" -->
Référencer le fichier de mot de passe vault
dans `ansible.cfg`
```none
[defaults]
vault_password_file = vault-password
```
__Bonnes pratiques avec vault__
* Lorsqu'on utilise vault, les variables et leurs valeurs sont offusquées, il n'est pas forcément évident d'assurer la maintenance sur ces fichiers de variables.
* Les bonnes pratiques Ansible préconisent de passer par une couche d'indirection, c'est à dire d'ajouter un fichier non chiffré dont les variables référenceront les variables vault.
* Créer un nouveau fichier nommé `vars` dans `group_vars/all`.
* Ajouter la variable et la faire pointer vers la variable vault.
* La structure du dossier de travail devient :
```none
.
├── ansible.cfg
├── inventories
   └── formation
   ├── group_vars
     └── all
     ├── vars <----- fichier d'indirection
     └── vault
   └── hosts
├── playbook-vault.yaml
└── vault-password
```
<!-- .slide: data-background="#2E2E2E" -->
Créer `inventories/formation/group_vars/all/vars`
```yaml
robert_password: "{{ vault_robert_password }}"
```
<small>La variable `robert_password` pointe sur
la variable `vault_robert_password` stockée dans le fichier `vault`.</small>
* Modifier le fichier playbook pour utiliser la variable provenant du fichier `vars`.
* Lancer le playbook.
<!-- .slide: data-background="#2E2E2E" data-state="small-code" -->
Modifier `playbook-vault.yaml`
```yaml
---
- hosts: debian9
tasks:
- name: Display secured password
debug:
msg: "Robert's password is: {{ robert_password }}"
```
Lancer le playbook
```none
$ ansible-playbook -i inventories/formation/hosts playbook-vault.yaml \
--vault-password-file vault-password
PLAY [debian9] *****************************************************************
TASK [Gathering Facts] *********************************************************
ok: [ansible-3]
TASK [Display secured password] ************************************************
ok: [ansible-3] => {
"msg": "Robert's password is: Mon super password !"
}
PLAY RECAP *********************************************************************
ansible-3 : ok=2 changed=0 unreachable=0 failed=0
```
__Pour aller plus loin__
Il est possible d'aller encore plus loin
avec les `vault-id` :
* https://docs.ansible.com/ansible/latest/user_guide/vault.html#vault-ids-and-multiple-vault-passwords
* https://dev.iachieved.it/iachievedit/ansible-vault-ids/

29
Pepiniere/Pepinière/devops/.gitlab-ci.yml

@ -0,0 +1,29 @@
variables:
GIT_SUBMODULE_STRATEGY: recursive
stages:
- build
build:
stage: build
image:
name: astefanutti/decktape:2.11.0
entrypoint: [""]
tags:
- france
- sii
script:
#
# 1. We change the size with --size due to a strange rendering bug
# as decribed here: https://github.com/astefanutti/decktape/issues/151
#
# 2. We also specify --chrome-arg=--disable-web-security to autorize
# Cross origin requests in chrome as described here:
# https://github.com/astefanutti/decktape/issues/157
#
- node /decktape/decktape.js --chrome-path chromium-browser --chrome-arg=--no-sandbox --chrome-arg=--disable-web-security --size='1576x1182' index.html speakup-devops.pdf
artifacts:
name: speakup-devops
expire_in: 8 days
paths:
- speakup-devops.pdf

3
Pepiniere/Pepinière/devops/.gitmodules vendored

@ -0,0 +1,3 @@
[submodule "revealjs"]
path = revealjs
url = ../../template-revealjs-sii-theme.git

52
Pepiniere/Pepinière/devops/0.introduction.md

@ -0,0 +1,52 @@
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![DevOps](images/devops_refactor.svg) <!-- .element: width="50%" -->
__Introduction au DevOps__
Alexan Andrieux | Christian Tritten
<small>Speak Up SII - 25 mars 2021</small>
<!-- .slide: data-state="medium-code" -->
<div class="columns">
<div>
## Alexan Andrieux
SII Rennes
Ingénieur DevOps
</div>
<div>
## Christian Tritten
SII Rennes
Ingénieur DevOps
</div>
</div>
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
## Introduction au DevOps
De quoi on va parler aujourd'hui ?
1. Constats du travail en Silo
2. Le DevOps
3. Les origines du DevOps
4. La pratique du DevOps
5. Mise en place du DevOps
6. Conclusion

163
Pepiniere/Pepinière/devops/1.constats.md

@ -0,0 +1,163 @@
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
## Constats du travail en Silo
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Deux mondes opposés
Dev vs Ops
![versus](images/versus-retro-style.jpg) <!-- .element: width="50%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Le monde du Dev
But des développeurs :
- Créer de nouveaux logiciels/librairies
- Développer des nouvelles fonctionnalités
- Améliorer le code existant (performance, élégance, maintenabilité)
- Versionner du code
- Tester facilement
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Le monde du Dev
- Organisé en sprint (Agilité)
- Changement fréquent de l'application
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Le monde du Dev
Impacts possibles :
- sécurité
- stabilité
- performances
- l'introduction de bug
- mise à jour et/ou réinstallation d'application
- augmentation des ressources systèmes utilisées
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Le monde de l'Ops
Objectifs :
- déployer et maintenir des plateformes
* stables,
* sécurisées
* performantes
- administrer facilement les plateformes
- avoir de la visibilité sur les incidents qui surviennent, voire anticiper l'arrivée des incidents (monitoring)
- pouvoir réparer rapidement (procédures)
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Le monde de l'Ops
- Généralement organisé via des outils de ticketing (ITIL)
- Tout changement doit être motivé et tamponné (objectif : stabilité)
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Le monde de l'Ops
Impacts possibles :
- Manque de réactivité sur les nouvelles demandes
- Contraintes fortes liées à la sécurité
- Peu (voir pas) de retour d'informations vers les Dev
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### En résumé
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![dzon](images/people_twin.svg) <!-- .element: width="60%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Petites phrases de Devs...
- "Ça marche sur mon poste, donc ça doit fonctionner sur la VM..."
- "Comment ça quelle version de Java ? La dernière…"
- "C’est quoi ton serveur moisi ?"
- "C'est pas mon code le problème, c'est la VM"
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Petites phrases d'Ops
- "Ton code est vraiment tout pourri, c'est pas optimisé !"
- "Pas touche à mes plateformes !"
- "C'est pas la VM le problème, c'est ton application"
- "On ne peut pas faire confiance aux Devs !"
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
Constat n°1 : Le monde du dev ne comprend pas le monde de l'ops.
![wall](images/wallofconfusion.svg) <!-- .element: width="50%" -->
Constat n°2 : Le monde de l'ops ne comprend pas le monde du dev.
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Mise en lumière des problèmes avec l'Agilité
- 2 semaines d'intégration tous les 6 mois, ce n'est pas choquant
- 2 semaines d'intégration toutes les 2 semaines (sprint) ça commence à devenir problématique
- On veut que lorsque la user story est finie, qu'elle soit vraiment finie !
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Mise en lumière des problèmes avec l'ITIL
- Il peut se passer (très) longtemps entre le commit et le déploiement en production
- La mise en production est un réel événement
- La mise en production sollicite un grand nombre de personnes

156
Pepiniere/Pepinière/devops/2.apport.md

@ -0,0 +1,156 @@
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
## Le DevOps
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Ce que n'est pas le DevOps
- une nouvelle technologie
- un nouveau métier ou nouvelle fonction dans l’entreprise
- une personne
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Une petite définition DevOps
>Le DevOps est une démarche visant l'adoption d'une _même culture dev et ops_ autour de méthodologies de travail et d'outils dans le but commun d'une _amélioration continue_ :
* de la productivité
* de la stabilité des process de développement (ci),
* de la qualité,
* et de la mise en production.
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
Il y a souvent une confusion entre __culture__ et __profil__ DevOps
Le DevOps est une __culture__.
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Le But
Le DevOps veut réconcilier ces deux mondes pour les faire travailler ensemble dans le but d'améliorer :
- le Time To Market (TTM)
- la qualité des développements
- la fiabilité des déploiements
![collaborate](images/collaborate.svg) <!-- .element: width="30%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Les Concepts
Le DevOps se base sur le modèle **CALMS** :
- **C** ulture commune
- **A** utomatisation des tâches répétitives
- **L** ean <small>(Amélioration Continue)</small>
- **M** esure
- **S** olidarité et partage
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### CALMS - la Culture
- Favorise la communication
- Réduit les incompréhensions
- Permet de mener un changement d'organisation et/ou de méthodologie
- Entretien l'esprit d'équipe et la motivation
- La productivité
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### CALMS - l'Automatisation
- Automatiser tout ce qui peut l'être
<small>Builds • Tests • Packaging • Cloud • Déploiements • Configuration • Chaos monkey</small>
- Assure la reproductibilité des actions
- Apporte de la traçabilité
- Évite les erreurs humaines
- Augmente la productivité
- Libère du temps pour les tâches à plus fortes valeurs ajoutées
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### CALMS - le Lean
- C'est une théorie de gestion inventée par Toyota
- Vise une recherche constante de la performance et de la qualité
Le __Lean__ permet de :
- supprimer les éléments inutiles et/ou complexes
- trouver des solutions d'amélioration
- résoudre les problèmes et d'en tirer les enseignements
- produire "juste ce qu'il faut" "juste à temps"
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### CALMS - la Mesure
- Identification des problèmes, des points d'améliorations,
mais aussi des réussites
- Identification des ressources utilisées, de la stabilité globale d'une plateforme
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### CALMS - la Solidarité
- Favorise la collaboration
- Favorise l'esprit d'équipe
- Amélioration du bien-être des personnes
- Amélioration de la productivité
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### CALMS - le Partage
- De l'information
- Des échecs et succès (rétros)
- Des responsabilités
- Des visions (opérationnelle, stratégique)
- Des techniques (outillage)
- Des expériences

83
Pepiniere/Pepinière/devops/3.origines.md

@ -0,0 +1,83 @@
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
## Les origines du DevOps
Le DevOps s'est essentiellement construit autour de l'_Agilité_ et du _Lean_.
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### L'Agilité
- Méthodes pour répondre au besoin : __comment s'organiser pour développer des produits complexes ?__
- Organisation en **Sprint**
![agilecycle](images/cycle_agile.svg) <!-- .element: width="100%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### L'Agilité : 4 valeurs
- La cohésion d'équipe
- La production d'application fonctionnelle
- La collaboration avec le client
- L'acceptation du changement
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### L'Agilité : 12 principes
![principeagile](images/principes_agile.svg) <!-- .element: width="70%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Emprunts du DevOps à l'agilité
- Cohésion et Communication
<small>(entre développeur et opérationnel)</small>
- Collaboration
<small>(développeur, opérationnel, business, client, ...)</small>
- Livraisons rapides et régulières
<small>(jusqu'à la mise en production)</small>
- Confiance et bienveillance
- Réactivité au changement
- Satisfaction client
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Le Lean Management du monde industriel
- Repose sur 5 grands principes (5P)
![5Plean](images/lean.svg) <!-- .element: width="30%" -->
- `Produit` <small>- conception au plus juste d’un produit (MVP = Minimum Valuable Product).</small>
- `Process` <small>- automatiser les tâches répétitives, amélioration continue</small>
- `Personnel` <small>- autonomie et efficacité dans le travail</small>
- `Performance` <small>- mesurer le progrès et combattre inefficacité</small>
- `Pilotage` <small>- logique de flux tiré (juste à temps), niveller la production (juste ce qu'il faut)</small>
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Emprunts du DevOps au Lean
- Automatisation des tâches répétitives
- Amélioration continue
- Mesure des difficultés et des progrès
- Efficacité dans le travail

66
Pepiniere/Pepinière/devops/4.pratique.md

@ -0,0 +1,66 @@
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
## La pratique du Devops
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### La démarche
La démarche DevOps, c'est l'Agilité et l'amélioration continue
de bout en bout :
![devops_scope](images/devops-scope.svg) <!-- .element: width="150%" -->
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### La démarche
Comparaison avec d'autres méthodologies :
![demarche](images/waterfall_agile_devops.svg) <!-- .element: width="90%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Cycle Agile VS Cycle DevOps
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![cycle_agile](images/cycle_agile.svg) <!-- .element: width="90%" -->
![cycle_devops](images/devops-toolchain-refactor.svg) <!-- .element: width="45%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### L'outillage
<!-- .slide: data-state="nologo-slide" -->
- `Plan` (Amélioration Continue)
![confluence](images/confluence.png)<!-- .element: width="50px" height="50px" --> ![trello](images/trello.png)<!-- .element: width="70px" height="50px" --> ![gitlab](images/gitlab.jpeg)<!-- .element: width="50px" height="50px" -->
- `Code`
![vscode](images/vscode.jpeg)<!-- .element: width="50px" height="50px" --> ![github](images/github.png)<!-- .element: width="50px" height="50px" --> ![gitlab](images/gitlab.jpeg)<!-- .element: width="50px" height="50px" -->
- `Build` (Intégration Continue)
![jenkins](images/jenkins.png)<!-- .element: width="50px" height="50px" --> ![travis](images/travis.png)<!-- .element: width="50px" height="50px" --> ![gitlab](images/gitlab.jpeg)<!-- .element: width="50px" height="50px" -->
- `Test` (Intégration Continue)
![selenium](images/selenium.png)<!-- .element: width="40px" height="40px" --> ![sonar](images/sonar.png)<!-- .element: width="70px" height="50px" --> ![checkmark](images/checkmarx.png)<!-- .element: width="70px" height="50px" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### L'outillage (suite)
- `Release` (Livraison Continue)
![jenkins](images/jenkins.png)<!-- .element: width="50px" height="50px" --> ![travis](images/travis.png)<!-- .element: width="50px" height="50px" --> ![gitlab](images/gitlab.jpeg)<!-- .element: width="50px" height="50px" -->
- `Deployment` (Déploiment continu)
![puppet](images/puppet.png)<!-- .element: width="70px" height="30px" --> ![ansible](images/ansible.png)<!-- .element: width="50px" height="50px" --> ![k8s](images/kubernetes.png)<!-- .element: width="70px" height="70px" -->
- `Operate` (Déploiment continu)
![bash](images/bash.png)<!-- .element: width="50px" height="40px" --> ![terraform](images/terraform.png)<!-- .element: width="60px" height="60px" --> ![k8s](images/kubernetes.png)<!-- .element: width="70px" height="70px" -->
- `Monitor` (Amélioration Continue)
![kibana](images/kibana.jpeg)<!-- .element: width="60px" height="50px" --> ![grafana](images/grafana.jpeg)<!-- .element: width="50px" height="50px" --> ![prometheus](images/prometheus.jpeg)<!-- .element: width="60px" height="50px" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### L'outillage
![xebialab](images/periodic_table_devops.png)

101
Pepiniere/Pepinière/devops/5.integration.md

@ -0,0 +1,101 @@
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
## Mise en place du Devops
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### DevOps et organisation
- Il n'existe pas de système d'organisation universel
pour mettre en place le DevOps
- Vous seul pouvez définir ce que DevOps signifie pour vous
- Le DevOps ne se résume pas uniquement à l'automatisation via des outils
- La démarche implique un changement de paradigme
<small>(modèle orienté projet => modèle orienté produit)</small>
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### La Finalité
- La transmission du savoir-faire
- Meilleur usage des infrastructures
- Simplicité
- Satisfaction client
- Réduction du TTM
- La mise en production doit devenir un non-évènement
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Les clefs du succès
- Apporter de l'énergie, proactivité et désir de connaissances
- Favoriser le travail d'équipe, se faire confiance, être bienveillant, se laisser le droit à l'erreur
- Partager les responsabilités, les problématiques, les succès et les échecs
- Optimiser l'environnement de travail pour favoriser le bien être et la productivité
- Encourager un management plus transparent
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Anti patterns
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Equipe Dev sans les Ops
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_without_ops](images/devops-topologies-anti-type-c-dev-don-t-need-ops.svg) <!-- .element: width="70%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Equipe Sysadmin avec un autre nom
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_rename](images/devops-topologies-anti-type-e-rebranded-sysadmin.svg) <!-- .element: width="70%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Equipe DevOps en silo
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_silo](images/devops-topologies-anti-type-b-devops-team-silo.svg) <!-- .element: width="70%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Patterns
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Collaboration Dev et Ops
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_collaborate](images/devops-topologies-type-1-dev-and-ops-collaboration.svg) <!-- .element: width="60%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Partage complet des responsabilités
### entre Dev et Ops
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_shared_responsability](images/devops-topologies-type-2-fully-shared-ops-responsabilities.svg) <!-- .element: width="40%" -->
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Evangélisation Devops
<!-- .slide: data-state="nologo-slide" style="text-align: center" -->
![team_evangelist](images/devops-topologies-type-6-devops-evangelists-team.svg) <!-- .element: width="70%" -->

80
Pepiniere/Pepinière/devops/6.conclusion.md

@ -0,0 +1,80 @@
## Conclusion
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Le DevOps implique
- une nouvelle façon de travailler ensemble
- une nouvelle organisation
- l'utilisation d'outils adaptés aux besoins
- de l'ouverture d'esprit, de la remise en question et éventuellement de la formation des équipes
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Pour le mettre en place, il faut
- une conduite du changement pour faire évoluer les comportements et les mentalités
- redéfinir le rythme via de nouveaux rituels en se basant par exemple sur l'Agilité
- tout le monde doit être acteur de la transformation (dev, ops, manager, métier, ...)
- ne pas avoir peur de l’échec, appendre de ces erreurs et s'améliorer en continue
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### DevOps et au-delà...
- DevSecOps
- SRE (Site Reliability Engineering)
<img src="images/alexan.jpg" width="30px" style="position: fixed; right: 0" />
### Meetups
- Devops Container:
<small>https://www.meetup.com/fr-FR/devops-containers/</small>
- Docker Paris:
<small>https://www.meetup.com/fr-FR/Docker-Paris/</small>
- Git Paris:
<small>https://www.meetup.com/fr-FR/git-Paris/</small>
- Kubernetes Paris:
<small>https://www.meetup.com/fr-FR/Kubernetes-Paris/</small>
- CNCF Paris:
<small>https://community.cncf.io/paris/</small>
- Rennes Devops:
<small>https://www.meetup.com/fr-FR/rennes-devops/</small>
- Nantes Devops:
<small>https://www.meetup.com/fr-FR/Nantes-DevOps/?_locale=fr-FR</small>
<img src="images/chris.png" width="30px" style="position: fixed; right: 0" />
### Liens utiles:
- Blog tech de la communauté DevOps:
<small>https://sii-ouest.gitlab.io/devops/blog/articles/demystfication-du-devops/item/</small>
- Blog tech et formation:
<small>https://enix.io/</small>
- Tuto de Xavki:
<small>https://xavki.blog/</small>
- Podcast des compagnons du DevOps et de radio DevOps:
<small>https://lydra.fr/blog/</small>
- Podcast et interview de Dev’Obs:
<small>https://devobs.p7t.tech/</small>
- Interview tech de Electro Monkeys:
<small>https://podcast.electro-monkeys.fr/</small>
- Les vidéos DevOps et tech de Krustyhack:
<small>https://www.youtube.com/channel/UCM0mnsNbecIi_IAPXtHb-TA</small>
## Des questions ?

8
Pepiniere/Pepinière/devops/Dockerfile

@ -0,0 +1,8 @@
FROM nginx:1.12.2
LABEL "com.example.vendor" = "SII Ouest"
LABEL version="1.0"
LABEL description="Speakup Devops"
LABEL maintainer="abegou@sii-ouest.com"
#COPY SOURCES FILES
COPY ./ /usr/share/nginx/html

10
Pepiniere/Pepinière/devops/README.md

@ -0,0 +1,10 @@
# DevOps
La vision du DevOps par SII.
## Jouer les slides en local
1. Cloner le dépôt :
`git clone --recurse-submodules https://gitlab.siinergy.net/sii-ouest/dejtechs/devops`
2. Dans Firefox ouvrir le fichier `index.html`

221
Pepiniere/Pepinière/devops/images/Devops-toolchain.svg

@ -0,0 +1,221 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 20.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 600 340" style="enable-background:new 0 0 600 340;" xml:space="preserve">
<style type="text/css">
.st0{fill:#353535;}
.st1{fill:#19838E;}
.st2{fill:#3737AA;}
.st3{fill:#8B9B29;}
.st4{fill:none;}
.st5{fill:#3FA9F5;}
.st6{fill:#F15A24;}
.st7{fill:#9263AB;}
.st8{fill:#AA2E2E;}
.st9{fill:#FFFFFF;}
</style>
<g>
<g>
<path class="st0" d="M158.9,167.9c0,3-0.9,5.3-2.6,6.9c-1.7,1.6-4.2,2.4-7.4,2.4h-5.2v-18.3h5.8c3,0,5.3,0.8,7,2.4
C158.1,162.9,158.9,165.1,158.9,167.9z M154.9,168c0-3.9-1.7-5.9-5.2-5.9h-2.1V174h1.7C153,174,154.9,172,154.9,168z"/>
<path class="st0" d="M175.2,177.2h-10.5v-18.3h10.5v3.2h-6.7v4h6.2v3.2h-6.2v4.7h6.7V177.2z"/>
<path class="st0" d="M191.4,158.9h3.9l-6.2,18.3h-4.2l-6.2-18.3h3.9l3.4,10.9c0.2,0.6,0.4,1.4,0.6,2.2c0.2,0.9,0.3,1.5,0.4,1.8
c0.1-0.8,0.4-2.1,0.9-4L191.4,158.9z"/>
</g>
<g>
<path class="st0" d="M421.4,168.1c0,3-0.8,5.4-2.3,7s-3.7,2.4-6.5,2.4c-2.8,0-5-0.8-6.5-2.4s-2.3-4-2.3-7c0-3,0.8-5.4,2.3-7
c1.5-1.6,3.7-2.4,6.5-2.4s5,0.8,6.5,2.4C420.6,162.7,421.4,165,421.4,168.1z M408,168.1c0,2,0.4,3.6,1.2,4.6
c0.8,1,1.9,1.6,3.5,1.6c3.1,0,4.6-2.1,4.6-6.2c0-4.1-1.5-6.2-4.6-6.2c-1.5,0-2.7,0.5-3.5,1.6C408.4,164.5,408,166,408,168.1z"/>
<path class="st0" d="M439.8,164.6c0,2-0.6,3.5-1.8,4.5c-1.2,1-3,1.6-5.3,1.6H431v6.5h-3.9v-18.3h5.9c2.2,0,3.9,0.5,5.1,1.4
C439.2,161.3,439.8,162.7,439.8,164.6z M431,167.5h1.3c1.2,0,2.1-0.2,2.7-0.7c0.6-0.5,0.9-1.2,0.9-2.1c0-0.9-0.2-1.6-0.7-2
c-0.5-0.4-1.3-0.7-2.3-0.7H431V167.5z"/>
<path class="st0" d="M456,172.1c0,1.7-0.6,3-1.8,3.9c-1.2,1-2.8,1.4-5,1.4c-2,0-3.7-0.4-5.2-1.1v-3.6c1.2,0.6,2.3,0.9,3.1,1.2
c0.9,0.2,1.6,0.3,2.3,0.3c0.9,0,1.5-0.2,2-0.5c0.5-0.3,0.7-0.8,0.7-1.5c0-0.4-0.1-0.7-0.3-1s-0.5-0.5-0.9-0.8
c-0.4-0.3-1.2-0.7-2.4-1.2c-1.1-0.5-2-1-2.5-1.5s-1-1-1.3-1.7c-0.3-0.6-0.5-1.4-0.5-2.3c0-1.6,0.5-2.9,1.6-3.8
c1.1-0.9,2.6-1.4,4.6-1.4c1,0,1.9,0.1,2.7,0.3c0.9,0.2,1.8,0.5,2.7,1l-1.3,3c-1-0.4-1.8-0.7-2.4-0.8c-0.6-0.2-1.3-0.2-1.9-0.2
c-0.7,0-1.3,0.2-1.7,0.5c-0.4,0.3-0.6,0.8-0.6,1.3c0,0.3,0.1,0.6,0.2,0.9c0.2,0.3,0.4,0.5,0.8,0.7c0.3,0.2,1.2,0.7,2.5,1.3
c1.7,0.8,2.9,1.6,3.5,2.5S456,171,456,172.1z"/>
</g>
<g>
<path class="st1" d="M180.2,75.6c47.4,5.4,84.2,45.6,84.2,94.4c0-38.8,13.3-74.6,35.6-102.9C271.6,31.1,228.7,7.2,180.2,4
l-13.9,35.8L180.2,75.6z"/>
</g>
<g>
<path class="st2" d="M159.3,264.5c-47.8-5-85-45.4-85-94.5c0-0.5,0-1.1,0-1.6l-35.2,13.7L3,168.1c0,0.6,0,1.3,0,1.9
c0,88.6,69.3,161,156.6,166l13.7-35.4L159.3,264.5z"/>
</g>
<g>
<path class="st0" d="M336,177C336,177,336,177,336,177C336,177,336,177,336,177z"/>
</g>
<g>
<path class="st0" d="M335.7,173.5c0-1.2-0.1-2.3-0.1-3.5c0,1.2,0,2.3,0,3.5c0,0,0,0,0,0L335.7,173.5z"/>
</g>
<g>
<path class="st3" d="M74.7,161.1c4.5-48.3,45.1-86.2,94.6-86.2c1.2,0,2.3,0,3.5,0.1l-13.7-35.2l14-36.1c-1.3,0-2.6,0-3.8,0
C80.5,3.7,7.9,73.3,3.2,161l35.9,13.9L74.7,161.1z"/>
</g>
<g>
<polygon class="st4" points="266,180.3 264.7,180.8 264.7,180.8 "/>
</g>
<g>
<g>
<path class="st5" d="M264.7,180.8L264.7,180.8c0,0,0-0.1,0-0.1L264.7,180.8z"/>
</g>
<g>
<path class="st5" d="M335.3,180.5L300.5,167l-34,13.2l0,0l-0.5,0.2l-1.3,0.5c0,0,0,0,0,0.1c0,0,0,0,0,0l-1,0.4
c-5.6,47.2-45.7,83.8-94.4,83.8c-0.9,0-1.8,0-2.7,0l13.8,35.7l-13.8,35.6c0.9,0,1.8,0,2.7,0c53,0,100.2-24.8,130.7-63.4
c0,0,0-0.1,0-0.1C320.3,247.1,333.1,215.2,335.3,180.5z"/>
</g>
<g>
<path class="st5" d="M264.7,180.7C264.7,180.7,264.7,180.7,264.7,180.7L264.7,180.7L264.7,180.7z"/>
</g>
</g>
<g>
<g>
<polygon class="st6" points="264.4,173.8 264.4,173.8 264.4,173.8 "/>
</g>
<g>
<path class="st6" d="M264.4,173.9L264.4,173.9C264.4,173.8,264.4,173.9,264.4,173.9L264.4,173.9z"/>
</g>
<g>
<path class="st6" d="M458.8,6.1c-9.2-1.6-18.6-2.4-28.1-2.4c-53,0-100.2,24.8-130.7,63.4c-22.3,28.3-35.6,64-35.6,102.9
c0,1.3,0,2.6,0,3.8l36.1-14l35.1,13.6c0-1.2,0-2.3,0-3.5c0-52.5,42.6-95,95-95c4.3,0,8.5,0.3,12.7,0.8l21.1-31.3L458.8,6.1z"/>
</g>
</g>
<g>
<path class="st7" d="M594.5,198.8c1.6-9.4,2.5-19,2.5-28.8c0-79.8-56.2-146.5-131.3-162.6l5.7,38.7l-20.9,31
c43,9.1,75.2,47.3,75.2,93c0,4.2-0.3,8.4-0.8,12.5l32.2,21.8L594.5,198.8z"/>
</g>
<g>
<path class="st8" d="M523.7,189.7c-9.1,43-47.3,75.4-93,75.4c-4.2,0-8.3-0.3-12.4-0.8L396.4,297l5.6,36.9
c9.3,1.6,18.9,2.5,28.7,2.5c79.6,0,146.1-55.9,162.5-130.6l-37.6,5.5L523.7,189.7z"/>
</g>
<g>
<path class="st1" d="M411.1,263c-39.7-8.3-70.2-41.3-74.9-82.2l-0.9-0.4c-2.2,34.8-15,66.7-35.3,92.4c23.4,29.7,56.8,51.2,95,59.6
l-5.6-37.1L411.1,263z"/>
</g>
<g>
<path class="st9" d="M327.8,94.9l3.1,2.3l-1.3,1.7l-8.2-6.1l1.8-2.4c0.8-1.1,1.6-1.8,2.4-2c0.8-0.2,1.6,0,2.4,0.6
c0.5,0.4,0.8,0.8,1,1.4c0.2,0.5,0.2,1.1,0,1.8c2.8,0.1,4.5,0.2,5.4,0.3l-1.4,1.9l-4.6-0.4L327.8,94.9z M326.4,93.8l0.4-0.6
c0.4-0.5,0.6-1,0.6-1.4c0-0.4-0.2-0.7-0.6-1c-0.4-0.3-0.8-0.4-1.1-0.2c-0.4,0.1-0.8,0.5-1.2,1.1l-0.4,0.5L326.4,93.8z"/>
<path class="st9" d="M339.8,86.4l-3.9,4.4l-7.7-6.7l3.9-4.4l1.3,1.2l-2.4,2.8l1.7,1.5l2.3-2.6l1.3,1.2l-2.3,2.6l2,1.7l2.4-2.8
L339.8,86.4z"/>
<path class="st9" d="M341.9,84.2l-7.2-7.3l1.5-1.5l5.9,6l2.9-2.9l1.3,1.3L341.9,84.2z"/>
<path class="st9" d="M352.9,74.2l-4.5,3.8l-6.6-7.8l4.5-3.8l1.2,1.3l-2.8,2.4l1.5,1.7l2.6-2.2l1.2,1.3l-2.6,2.2l1.7,2l2.8-2.4
L352.9,74.2z"/>
<path class="st9" d="M360.3,68.6l-2-1.5l-3,2.2l0.8,2.4l-1.9,1.4l-3.1-10.4l2.1-1.6l8.9,6.2L360.3,68.6z M356.8,65.9
c-1.8-1.4-2.9-2.2-3.1-2.3c-0.2-0.2-0.4-0.3-0.6-0.4c0.2,0.6,0.7,2,1.5,4.3L356.8,65.9z"/>
<path class="st9" d="M367.6,60.6c0.5,0.8,0.6,1.6,0.3,2.4c-0.3,0.8-0.9,1.5-1.9,2.1c-0.9,0.6-1.9,0.9-2.8,1l-1-1.7
c0.7-0.1,1.4-0.2,1.8-0.4c0.5-0.1,0.9-0.3,1.2-0.5c0.4-0.2,0.7-0.5,0.8-0.8c0.1-0.3,0.1-0.6-0.1-0.9c-0.1-0.2-0.2-0.3-0.4-0.4
c-0.2-0.1-0.4-0.1-0.7-0.1c-0.3,0-0.8,0-1.5,0.1c-0.7,0.1-1.2,0.1-1.6,0c-0.4-0.1-0.8-0.2-1.1-0.4c-0.3-0.2-0.6-0.5-0.9-0.9
c-0.5-0.8-0.6-1.5-0.3-2.3c0.3-0.8,0.8-1.4,1.8-2c0.5-0.3,0.9-0.5,1.4-0.6c0.5-0.1,1-0.3,1.6-0.3l0.3,1.8c-0.6,0.1-1,0.2-1.4,0.3
c-0.3,0.1-0.7,0.3-1,0.4c-0.3,0.2-0.6,0.5-0.7,0.7c-0.1,0.3-0.1,0.5,0.1,0.8c0.1,0.2,0.2,0.3,0.4,0.4c0.2,0.1,0.3,0.1,0.6,0.1
s0.7,0,1.5-0.1c1.1-0.1,1.8-0.1,2.4,0.1C366.9,59.6,367.3,60,367.6,60.6z"/>
<path class="st9" d="M376.8,58.9l-5.2,2.7l-4.7-9.1l5.2-2.7l0.8,1.6l-3.3,1.7l1,2l3.1-1.6l0.8,1.6l-3.1,1.6l1.2,2.3l3.3-1.7
L376.8,58.9z"/>
</g>
<g>
<path class="st9" d="M233.1,56.1c-0.5,1-1.2,1.6-2.1,1.8c-0.9,0.2-1.9,0-3-0.6l-0.8-0.4l-1.7,3.2l-1.9-1l4.7-9l2.9,1.5
c1.1,0.6,1.8,1.2,2.1,2C233.6,54.3,233.5,55.2,233.1,56.1z M228,55.3l0.6,0.3c0.6,0.3,1.1,0.4,1.5,0.3c0.4-0.1,0.7-0.3,1-0.8
c0.2-0.5,0.3-0.8,0.2-1.2c-0.1-0.3-0.5-0.6-1-0.9l-0.9-0.5L228,55.3z"/>
<path class="st9" d="M232.2,63.8l5.4-8.7l1.8,1.1l-4.4,7.1l3.5,2.2l-0.9,1.5L232.2,63.8z"/>
<path class="st9" d="M244.8,72.3l0.8-2.4l-3-2.2l-2,1.5l-1.9-1.4l9-6.1l2.1,1.6l-3.2,10.4L244.8,72.3z M246.3,68.1
c0.8-2.2,1.2-3.4,1.3-3.7c0.1-0.3,0.2-0.5,0.3-0.7c-0.5,0.4-1.7,1.3-3.7,2.8L246.3,68.1z"/>
<path class="st9" d="M255.1,81.1l-2-1.8l1.8-8.7l0,0c-0.8,1.1-1.5,1.8-1.8,2.3l-3.2,3.6l-1.4-1.3l6.8-7.6l2,1.8l-1.8,8.6l0,0
c0.8-1,1.4-1.8,1.8-2.2l3.2-3.6l1.4,1.3L255.1,81.1z"/>
</g>
<g>
<path class="st9" d="M55.7,102.8c-0.4,0.7-0.5,1.4-0.2,2.1c0.3,0.7,0.9,1.3,1.9,1.9c2,1.1,3.4,1,4.2-0.5c0.4-0.6,0.6-1.5,0.8-2.5
l1.6,0.9c-0.1,0.9-0.4,1.8-1,2.7c-0.7,1.3-1.7,2-2.9,2.3c-1.2,0.2-2.5-0.1-3.9-0.9c-0.9-0.5-1.6-1.2-2.1-1.9
c-0.5-0.7-0.7-1.5-0.8-2.4c0-0.8,0.2-1.7,0.7-2.5c0.5-0.9,1.2-1.6,2.1-2.2l1.2,1.5c-0.3,0.2-0.7,0.5-1,0.8
C56.2,102.2,55.9,102.5,55.7,102.8z"/>
<path class="st9" d="M64.1,98.3l3.2,2.2l-1.2,1.8l-8.4-5.8l1.7-2.4c0.8-1.1,1.6-1.8,2.4-2.1c0.8-0.3,1.6-0.1,2.5,0.5
c0.5,0.3,0.8,0.8,1,1.3c0.2,0.5,0.2,1.1,0.1,1.8c2.8,0.1,4.5,0.1,5.4,0.1l-1.4,2l-4.6-0.2L64.1,98.3z M62.7,97.3l0.4-0.6
c0.4-0.6,0.6-1,0.6-1.4c0-0.4-0.2-0.7-0.6-1c-0.4-0.3-0.8-0.3-1.1-0.2c-0.4,0.2-0.7,0.5-1.1,1.1l-0.4,0.5L62.7,97.3z"/>
<path class="st9" d="M75.8,89.4l-3.7,4.5l-7.9-6.5l3.7-4.5l1.4,1.1l-2.3,2.9l1.7,1.4l2.2-2.7l1.4,1.1l-2.2,2.7l2,1.7l2.3-2.9
L75.8,89.4z"/>
<path class="st9" d="M82.1,82.6l-2.3-1.1l-2.6,2.7l1.2,2.2l-1.6,1.7L72,78.4l1.8-1.9l9.9,4.5L82.1,82.6z M78.2,80.6
c-2.1-1-3.2-1.6-3.5-1.8c-0.3-0.1-0.5-0.3-0.6-0.3c0.3,0.5,1.1,1.9,2.3,4L78.2,80.6z"/>
<path class="st9" d="M88.3,76.9l-1.6,1.4L81.1,72L79,73.9l-1.2-1.3l5.8-5.1l1.2,1.3l-2.1,1.8L88.3,76.9z"/>
<path class="st9" d="M97,70l-4.7,3.6l-6.2-8.1l4.7-3.6l1.1,1.4l-3,2.3l1.4,1.8l2.7-2.1l1.1,1.4l-2.7,2.1l1.6,2.1l3-2.3L97,70z"/>
</g>
<g>
<path class="st9" d="M68.4,241.5l1.2,1.8l-10.4,2.9l-1.3-1.9l6.5-8.6l1.2,1.8l-3.9,5c-0.2,0.3-0.5,0.6-0.8,1
c-0.3,0.4-0.6,0.6-0.7,0.7c0.4-0.2,1.1-0.5,2.2-0.8L68.4,241.5z"/>
<path class="st9" d="M66.6,255.9l-3.7-4.6l8-6.4l3.7,4.6l-1.4,1.1l-2.3-2.9l-1.8,1.4l2.2,2.7l-1.4,1.1l-2.2-2.7l-2.1,1.6l2.3,2.9
L66.6,255.9z"/>
<path class="st9" d="M73.3,257.6l-2.9,2.7l-1.5-1.6l7.5-6.9l2,2.2c0.9,1,1.5,1.9,1.5,2.8c0.1,0.8-0.3,1.6-1,2.3
c-0.4,0.4-0.9,0.7-1.5,0.7c-0.6,0.1-1.2,0-1.8-0.3c-0.6,2.7-1,4.4-1.2,5.2l-1.6-1.8l1.2-4.4L73.3,257.6z M74.6,256.4l0.5,0.5
c0.5,0.5,0.9,0.8,1.3,0.9s0.8,0,1.1-0.4c0.4-0.3,0.5-0.7,0.4-1.1c-0.1-0.4-0.4-0.8-0.8-1.3l-0.4-0.5L74.6,256.4z"/>
<path class="st9" d="M76.5,266.5l7-7.4l1.6,1.5l-7,7.4L76.5,266.5z"/>
<path class="st9" d="M82.7,272.1l-1.6-1.4l6.6-7.8l4.5,3.8l-1.1,1.4l-2.8-2.4l-1.7,2l2.6,2.2l-1.1,1.3l-2.6-2.2L82.7,272.1z"/>
<path class="st9" d="M94.4,273.6l4.2-2.2l1.9,1.4l-6.4,3.1l-2.3,3.2l-1.7-1.3l2.3-3.2l1-7.1l1.9,1.4L94.4,273.6z"/>
</g>
<g>
<path class="st9" d="M464.4,299.4l-4.5-7.1l-0.1,0c0.5,1.5,0.8,2.6,1,3.1l1.2,4.6l-1.9,0.5l-2.7-9.8l2.8-0.8l4.4,6.9l0,0l0.4-8.2
l2.8-0.8l2.7,9.8l-1.9,0.5l-1.3-4.7c-0.1-0.2-0.1-0.5-0.2-0.8c-0.1-0.3-0.2-1.1-0.5-2.3l-0.1,0l-0.5,8.4L464.4,299.4z"/>
<path class="st9" d="M481.6,288.2c0.6,1.6,0.7,2.9,0.2,4.1c-0.5,1.1-1.4,2-2.9,2.6c-1.5,0.6-2.7,0.6-3.8,0c-1.1-0.5-2-1.6-2.6-3.2
c-0.6-1.6-0.7-2.9-0.2-4.1c0.5-1.1,1.4-2,2.9-2.6c1.5-0.6,2.7-0.6,3.8,0C480.1,285.6,480.9,286.6,481.6,288.2z M474.6,290.9
c0.4,1.1,0.9,1.8,1.5,2.2c0.6,0.4,1.3,0.4,2.1,0.1c1.6-0.6,2-2,1.2-4.1c-0.8-2.1-2-2.9-3.6-2.3c-0.8,0.3-1.3,0.8-1.5,1.5
C474.1,288.9,474.2,289.8,474.6,290.9z"/>
<path class="st9" d="M495,287.3l-2.5,1.2l-7.4-4.9l-0.1,0c0.7,1.2,1.2,2,1.4,2.5l2.2,4.3l-1.7,0.9l-4.6-9.1l2.4-1.2l7.4,4.8l0,0
c-0.7-1.2-1.1-2-1.4-2.5l-2.2-4.3l1.7-0.9L495,287.3z"/>
<path class="st9" d="M498.5,285.3l-5.2-8.8l1.9-1.1l5.2,8.8L498.5,285.3z"/>
<path class="st9" d="M507,279.8l-1.8,1.2l-4.7-6.9l-2.3,1.6l-1-1.5l6.4-4.3l1,1.5l-2.3,1.6L507,279.8z"/>
<path class="st9" d="M515.8,266.6c1.1,1.3,1.6,2.6,1.5,3.8c-0.1,1.2-0.7,2.3-1.9,3.3c-1.2,1-2.4,1.4-3.6,1.2
c-1.2-0.2-2.4-0.9-3.4-2.2c-1.1-1.3-1.6-2.6-1.5-3.8c0.1-1.2,0.7-2.3,1.9-3.3c1.2-1,2.4-1.4,3.6-1.2
C513.6,264.5,514.7,265.2,515.8,266.6z M510,271.3c0.7,0.9,1.4,1.4,2.1,1.6c0.7,0.2,1.4,0,2-0.6c1.3-1.1,1.3-2.5-0.2-4.3
c-1.5-1.8-2.8-2.1-4.2-1c-0.7,0.5-1,1.2-1,1.9C508.9,269.6,509.3,270.4,510,271.3z"/>
<path class="st9" d="M520.6,263.7l2.7,2.8l-1.5,1.5l-7.1-7.3l2.1-2.1c1-1,1.9-1.5,2.7-1.6c0.8-0.1,1.6,0.2,2.3,0.9
c0.4,0.4,0.7,0.9,0.8,1.5c0.1,0.6,0,1.2-0.2,1.8c2.7,0.6,4.5,0.9,5.3,1.1l-1.7,1.7l-4.5-1.1L520.6,263.7z M519.4,262.4l0.5-0.5
c0.5-0.5,0.8-0.9,0.8-1.3c0.1-0.4-0.1-0.8-0.4-1.1c-0.3-0.3-0.7-0.5-1.1-0.4c-0.4,0.1-0.8,0.4-1.3,0.9l-0.5,0.5L519.4,262.4z"/>
</g>
<g>
<path class="st9" d="M235,279.1c0.5,1,0.6,1.9,0.3,2.7c-0.3,0.8-1.1,1.5-2.2,2.1l-0.8,0.4l1.7,3.2l-1.9,1l-4.8-9l2.9-1.5
c1.1-0.6,2-0.8,2.9-0.6C233.8,277.6,234.5,278.1,235,279.1z M231.4,282.8l0.6-0.3c0.6-0.3,1-0.7,1.1-1c0.2-0.4,0.1-0.8-0.1-1.2
c-0.2-0.4-0.5-0.7-0.9-0.8c-0.4-0.1-0.8,0-1.3,0.3l-0.9,0.5L231.4,282.8z"/>
<path class="st9" d="M246.6,280.1l-1.9-1.6l-3.1,2l0.7,2.4l-2,1.3l-2.6-10.6l2.2-1.4l8.6,6.6L246.6,280.1z M243.2,277.2
c-1.8-1.5-2.8-2.3-3-2.5c-0.2-0.2-0.4-0.4-0.5-0.5c0.2,0.6,0.6,2.1,1.3,4.4L243.2,277.2z"/>
<path class="st9" d="M249,267.7c-0.6,0.5-1,1.1-0.9,1.9c0,0.8,0.4,1.6,1,2.4c1.4,1.8,2.8,2.2,4.1,1.1c0.6-0.4,1.1-1.1,1.7-2
l1.1,1.4c-0.4,0.8-1.1,1.5-1.9,2.1c-1.2,0.9-2.3,1.3-3.5,1c-1.2-0.2-2.3-1-3.3-2.3c-0.7-0.8-1.1-1.7-1.3-2.6
c-0.2-0.9-0.1-1.7,0.2-2.5c0.3-0.8,0.8-1.5,1.6-2.1c0.8-0.6,1.7-1,2.8-1.3l0.5,1.8c-0.4,0.1-0.8,0.2-1.2,0.3
C249.6,267.3,249.3,267.4,249,267.7z"/>
<path class="st9" d="M265.2,264.8l-1.8,1.7l-4.9-1.3l-0.2,1.1l2.5,2.7l-1.6,1.5l-6.9-7.5l1.6-1.5l3.2,3.4l-0.2-1.5l-0.3-4.4
l1.8-1.6l0.5,5.7L265.2,264.8z"/>
<path class="st9" d="M271.4,258l-2.3-1.1l-2.5,2.8l1.3,2.2l-1.6,1.7l-5.2-9.5l1.8-2l10,4.2L271.4,258z M267.4,256.1
c-2.1-1-3.3-1.5-3.5-1.6c-0.3-0.1-0.5-0.2-0.6-0.3c0.3,0.5,1.1,1.8,2.4,3.9L267.4,256.1z"/>
<path class="st9" d="M272.6,247.5l2.4-3.2l4.2,3.2c-0.2,0.7-0.5,1.2-0.8,1.8c-0.3,0.5-0.6,1-1,1.5c-0.9,1.2-2,1.9-3.2,2
c-1.2,0.1-2.5-0.4-3.8-1.4c-1.3-1-2.1-2.1-2.2-3.4c-0.2-1.3,0.2-2.6,1.2-4c0.6-0.8,1.4-1.5,2.3-2l1,1.6c-0.7,0.4-1.4,0.9-1.8,1.5
c-0.6,0.7-0.8,1.5-0.6,2.4c0.2,0.8,0.7,1.6,1.5,2.2c0.9,0.7,1.7,1,2.4,1c0.7,0,1.4-0.4,1.9-1.1c0.3-0.4,0.5-0.8,0.7-1.2l-1.7-1.3
l-1.2,1.5L272.6,247.5z"/>
<path class="st9" d="M284.9,239.4l-3.1,5l-8.6-5.4l3.1-5l1.5,0.9l-2,3.1l1.9,1.2l1.8-2.9l1.5,0.9l-1.8,2.9l2.2,1.4l2-3.1
L284.9,239.4z"/>
</g>
<g>
<path class="st9" d="M516.7,69.9c-0.6-0.5-1.3-0.7-2-0.5c-0.7,0.2-1.5,0.7-2.2,1.5c-1.5,1.7-1.6,3.2-0.3,4.3
c0.5,0.5,1.3,0.9,2.3,1.3l-1.2,1.4c-0.9-0.3-1.7-0.7-2.5-1.4c-1.1-1-1.7-2-1.7-3.2c0-1.2,0.5-2.4,1.6-3.7c0.7-0.8,1.4-1.4,2.2-1.8
c0.8-0.4,1.6-0.5,2.5-0.3c0.8,0.1,1.6,0.5,2.4,1.2c0.8,0.6,1.4,1.5,1.8,2.5l-1.7,0.9c-0.2-0.4-0.4-0.8-0.6-1.1
C517.2,70.4,517,70.1,516.7,69.9z"/>
<path class="st9" d="M525.5,83.1c-1.2,1.2-2.4,1.8-3.7,1.8c-1.2,0-2.4-0.5-3.5-1.6c-1.1-1.1-1.6-2.3-1.6-3.5
c0.1-1.2,0.7-2.4,1.9-3.6c1.2-1.2,2.4-1.8,3.7-1.8c1.2,0,2.4,0.5,3.5,1.6c1.1,1.1,1.6,2.3,1.6,3.5
C527.4,80.7,526.7,81.9,525.5,83.1z M520.3,77.8c-0.8,0.8-1.3,1.6-1.4,2.3s0.1,1.4,0.7,2c1.2,1.2,2.6,1,4.3-0.6
c1.6-1.6,1.9-3,0.6-4.3c-0.6-0.6-1.3-0.9-2-0.8C521.9,76.6,521.1,77,520.3,77.8z"/>
<path class="st9" d="M529.5,96l-1.7-2.2l3.3-8.3l0,0c-1,0.9-1.7,1.6-2.2,1.9l-3.8,3l-1.2-1.5l8-6.3l1.7,2.1l-3.2,8.2l0,0
c1-0.9,1.7-1.5,2.1-1.8l3.8-3l1.2,1.5L529.5,96z"/>
<path class="st9" d="M532.7,100.5l-1.2-1.8l8.4-5.7l3.3,4.8l-1.5,1l-2.1-3.1l-2.2,1.5l1.9,2.9l-1.5,1l-1.9-2.9L532.7,100.5z"/>
<path class="st9" d="M536.3,106.1l8.8-5.2l1.1,1.9l-8.8,5.2L536.3,106.1z"/>
<path class="st9" d="M546,111.8l1.8,3.6l-4.7,2.4c-0.5-0.5-0.9-1-1.2-1.5c-0.3-0.5-0.6-1-0.9-1.5c-0.7-1.4-0.8-2.6-0.4-3.8
c0.4-1.1,1.4-2.1,2.9-2.8c1.5-0.7,2.8-0.9,4.1-0.5c1.2,0.4,2.2,1.4,3,2.9c0.5,0.9,0.7,1.9,0.8,3l-1.9,0.1c0-0.8-0.2-1.6-0.5-2.3
c-0.4-0.8-1-1.4-1.9-1.6c-0.8-0.2-1.7-0.1-2.6,0.4c-1,0.5-1.6,1.1-2,1.8c-0.3,0.7-0.3,1.4,0.1,2.2c0.2,0.4,0.5,0.8,0.7,1.2l1.9-1
l-0.9-1.7L546,111.8z"/>
<path class="st9" d="M556.6,125l-6.1,2.4c-0.7,0.3-1.4,0.4-2,0.3s-1.2-0.4-1.7-0.9c-0.5-0.5-0.9-1.1-1.2-1.9
c-0.5-1.2-0.5-2.3-0.2-3.2c0.4-0.9,1.1-1.6,2.2-2l6.1-2.4l0.8,2l-5.8,2.3c-0.7,0.3-1.2,0.6-1.4,1.1c-0.2,0.4-0.2,1,0.1,1.7
c0.3,0.7,0.6,1.1,1.1,1.2c0.5,0.2,1.1,0.1,1.8-0.2l5.8-2.3L556.6,125z"/>
<path class="st9" d="M552.5,132.9l-3.8,1.1l-0.6-2.1l9.8-2.9l0.8,2.9c0.4,1.3,0.4,2.4,0.1,3.2c-0.3,0.8-0.9,1.3-1.9,1.6
c-0.6,0.2-1.1,0.2-1.7,0c-0.5-0.2-1-0.5-1.4-1c-1.8,2.1-2.9,3.5-3.4,4.1l-0.7-2.3l3.1-3.4L552.5,132.9z M554.2,132.4l0.2,0.7
c0.2,0.7,0.4,1.1,0.8,1.4c0.3,0.2,0.7,0.3,1.2,0.2c0.5-0.1,0.7-0.4,0.8-0.8c0.1-0.4,0.1-0.9-0.1-1.6l-0.2-0.6L554.2,132.4z"/>
<path class="st9" d="M552.1,147.6l-1.2-5.7l10-2.1l1.2,5.7l-1.7,0.4l-0.8-3.6l-2.2,0.5l0.7,3.4l-1.7,0.4l-0.7-3.4l-2.6,0.5
l0.8,3.6L552.1,147.6z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save