- EPSI B3 2016/2017 - David Gayerie Licence Creative Commons

Ansible est un outil d'automatisation pour la maintenance de systèmes et le déploiement d'applications.

Ansible permet de définir une liste de machines en les associant à des groupes. L'ensemble de ces groupes est appelé un inventaire (inventory). Il est ensuite possible de réaliser des tâches sur un ou plusieurs groupes (et donc une ou plusieurs machines) en faisant appel à des modules. Pour chaque module, Ansible établit une connexion SSH machine par machine et vérifie si des commandes doivent être exécutées selon l'état de la machine et, le cas échéant, les exécute.

Il est possible de regrouper un ensemble de tâches dans un playbook qui va définir l'état d'un groupe de machines. Lorsqu'on exécute un playbook, Ansible ne va effectuer que les actions nécessaires pour rendre la machine conforme au playbook.

Installation

Ansible est écrit en Python et est disponible dans les dépôt Linux. Pour un système type Debian, vous pouvez utiliser apt :


sudo apt install ansible
			

Si vous avez l'habitude d'utiliser l'écosystème Python alors vous pouvez utiliser un environnement virtualisé Python 3 et ensuite installer Ansible à partir du gestionnaire python pip :


virtualenv -p /usr/bin/python3 venv
source venv/bin/activate
pip install ansible
			
Pour plus d'informations sur l'installation, vous pouvez vous reporter à la documentation.

Création d'un inventaire

Un inventaire (inventory) est un catalogue des noms ou adresses de machines (aussi appelées nœuds ou hosts) décrivant une infrastructure.

Par défaut, l'inventaire se trouve dans le fichier /etc/ansible/hosts. Il est également possible de préciser à Ansible d'utiliser un inventaire particulier, ce qui évite de modifier le fichier système, notamment pour les phases de test.

Le fichier d'inventaire suit le format de fichier INI :

Format général d'un inventaire

[NOM_GROUPE]
ma-machine
ma-machine2

[NOM_GROUPE2]
autre-machine
autre-machine2
				

Il est possible de définir un groupe comme étant un ensemble d'autres groupes grâce à la syntaxe [NOM_GROUPE:children]. Ce groupe ne contient alors que des noms d'autres groupes de l'inventaire.

Si les machines sont numérotées, vous pouvez utiliser une syntaxe abrégée de la forme racine<01>:<09> pour eviter de lister une machine par ligne.

Exemple d'un inventaire

[web]
web01:04
dmz.web01:05

[sql]
mysql01:02

[supervisor]
192.10.0.32

[backup:children]
web
sql
				

Il existe un groupe implicite : all. Ce groupe désigne l'ensemble des machines décrites dans l'inventaire.

Les machines présentes dans l'inventaire doivent être administrables par Ansible. Pour cela, il faut que chaque machine soit accessible via SSH et qu'une version de Python >=2.7 y soit installée. De plus, pour administrer correctement la machine, il est probablement nécessaire que le compte utilisateur pour la connexion SSH puisse obtenir des privilèges d'exécution (par exemple avec la commande sudo).

Exécution de Ansible

Vous pouvez exécuter ansible avec les paramètres suivants :

-i <fichier inventaire>
spécifie le fichier d'inventaire à utiliser.
-C, --check
ne fait aucun changement. Ansible va se contenter de deviner les modifications qui devraient être realisées sur les machines.
-m <nom du module>
spécifie le module que l'on souhaite invoquer.
-a <arguments>
spécifie les arguments à passer au module au moment de l'exécution.
-k
demande le mot de passe pour la connexion SSH
-u <utilisateur>
spécifie le login utilisateur pour la connexion SSH
-b, --become
exécute les commandes distantes en tant que superutilisateur
-K
demande le mot de passe pour les opérations demandant des privilèges (principalement lors de l'exécution d'une commande sudo sur la machine distante)

Vous pouvez par exemple tester votre inventaire en utilisant le module ping pour vous assurer que vous pouvez joindre toutes les machines de votre inventaire :


ansible -k -i <fichier inventaire> <groupe> -m ping
			

Exercice : création d'un machine avec LXC

Objectif
Disposer d'un conteneur LXC de référence administrable avec Ansible

Reprenez votre script de création de machine écrit lors du chapitre sur LXC et ajoutez les instructions nécessaires pour avoir une machine administrable avec Ansible.

Commandes pour LXC/LXD

lxc launch images:ubuntu/xenial/amd64 <nom du conteneur>
lxc exec <nom du conteneur> -- apt update
lxc exec <nom du conteneur> -- apt -y upgrade
lxc exec <nom du conteneur> -- apt -y install openssh-server sudo python
lxc exec <nom du conteneur> -- adduser $USER
lxc exec <nom du conteneur> -- usermod -a -G sudo $USER
			
Commandes pour LXC seul

sudo lxc-create --template download --name <nom du conteneur> -- -d ubuntu -r xenial -a amd64
sudo lxc-start -n <nom du conteneur>
sudo lxc-attach -n <nom du conteneur> -- apt update
sudo lxc-attach -n <nom du conteneur> -- apt -y upgrade
sudo lxc-attach -n <nom du conteneur> -- apt -y install openssh-server sudo python
sudo lxc-attach -n <nom du conteneur> -- adduser $USER
sudo lxc-attach -n <nom du conteneur> -- usermod -a -G sudo $USER
			

Exercice : première utilisation d'Ansible

Objectif
comprendre le fonctionnement d'Ansible

Créez deux conteneurs à partir de celui créé à l'exercice précédent. Créez un inventaire Ansible en mettant chaque machine dans un groupe différent (par exemple groupe1 et groupe2).

Exécutez ensuite ansible :


ansible -k -i <fichier inventaire> groupe1 -m ping
ansible -k -i <fichier inventaire> groupe2 -m ping
ansible -k -i <fichier inventaire> all -m ping
		

Essayez ensuite d'utiliser le module raw qui permet d'exécuter n'importe quelle commande sur les machines distantes :

Exemple d'utilisation du module raw pour exécuter la commande date

ansible -k -i <fichier inventaire> <groupe> -m raw -a "date"
			

Utilisez le module raw pour exécuter des commandes nécessitant des privilèges comme apt update.

Écriture de playbooks

Un playbook est à la fois un format de fichier et une arborescence de fichiers permettant de définir l'état d'une infrastructure de machines. Avec les playbooks, nous avons à notre disposition un outil qui nous permet de gérer notre infrastructure comme du code : c'est-à-dire que la gestion des machines se fait à partir de fichiers semblables à du code source applicatif. Il devient donc possible d'utiliser des gestionnaires de source comme Git pour conserver, partager et versionner notre infrastructure mais également d'imaginer des procédures automatisées de test et de déploiement non seulement des applicatifs mais également des machines.

Dans son sens le plus strict, un playbook est un fichier au format YAML.

Exemple de fichier playbook

---
- hosts: web

  tasks:
    - name: checks apache2 is present
      package: name=apache2 state=present

				

Un fichier playbook peut possèder les sections suivantes :

hosts
Le nom de groupe de l'inventaire pour lequel s'applique le playbook
vars
Une liste de variables qui peuvent être utilisées dans le corps du playbook en utilisant la notation Jinja2 {{ nom_variable }}
remote_user
Le login de l'utilisateur distant utilisé pour réaliser les tâches
tasks
La liste des tâches à réaliser si nécessaire
handlers
La liste des actions qui pourront être exécutées lors d'une notification

Dans les sections tasks et handlers, on trouve la déclaration des modules avec leurs arguments. Pour chacun, on utilisera soit la notation :


  - name: <description de la tâche>
    <module>: <arg1>=<valeur1> <arg2>=<valeur2>...
			

... soit la notation plus longue :


  - name: <description de la tâche>
    <module>: 
      <arg1>: <valeur1>
      <arg2>: <valeur2>
      ...
			

Les handlers permettent de définir des modules qui ne seront appelés que si certaines tâches sont exécutées. On ajoute l'attibut notify à une tâche pour indiquer que si la tâche est exécutée alors le handler doit aussi l'être

Exemple d'utilisation d'un handler

---
- hosts: web
  remote_user: root

  handlers:
    - name : reload apache2 service
      service: name=apache2 state=reloaded enabled=yes

  tasks:
    - name: checks apache2 is present
      package: name=apache2 state=present

    - name: checks apache2 modules enabled
      apache2_module: name=ssl state=present
      notify:
        - reload apache2 service
				

L'exemple ci-dessus vérifie que le serveur Web Apache est installé et que le module ssl est activé pour ce serveur. Si ce n'est pas le cas, alors ansible installera la module puis notifiera le handler "reload apache2 service". Ce dernier effectuera une reload de la configuration du serveur. Les handlers sont donc une façon simple de définir des tâches conditionnelles.

Exécution d'un playbook

Vous pouvez exécuter ansible-playbook avec les paramètres suivants :

-i <fichier inventaire>
spécifie le fichier d'inventaire à utiliser.
-C, --check
ne fait aucun changement. Ansible va se contenter de deviner les modifications qui devraient être realisées sur les machines.
-k
demande le mot de passe pour la connexion SSH
-u <utilisateur>
spécifie le login utilisateur pour la connexion SSH
-b, --become
exécute les commandes distantes en tant que superutilisateur
-K
demande le mot de passe pour les opérations demandant des privilèges (principalement lors de l'exécution d'une commande sudo sur la machine distante)
Exemple d'exécution d'un playbook

ansible-playbook -i <inventaire> -k -K -b monplaybook.yml
				

Exercice : premier playbook

Objectif
utiliser ansible-playbook

Exécuter le playbook suivant sur un conteneur LXC :


---
- hosts: web

  handlers:
    - name : reload apache2 service
      service: name=apache2 state=reloaded enabled=yes

  tasks:
    - name: checks apache2 is present
      package: name=apache2 state=present

    - name: checks apache2 modules enabled
      apache2_module: name=ssl state=present
      notify:
        - reload apache2 service
		

Vérifier que le serveur HTTP est bien disponible.

Relancez le même playbook pour voir ce qu'il se passe...

Exercice : hébergement du cours

Objectif
Utiliser ansible-playbook pour monter un serveur Web qui héberge ce cours.

Une archive du site est téléchargeable à cette adresse. Mais ce site est également un dépôt GitHub sur la branche gh-pages.

Testez votre playbook avec un conteneur LXC.

Sauvegardez votre projet dans un dépôt GitHub !