Vous n’arrivez plus à gérer votre ferme de serveurs ? Vous ne savez plus quelles versions ont été déployées ?
Avec Ansible, nous écrirons un scénario pour installer vos serveurs et mémoriser leur configuration.
Présentation
Ansible permet d’installer des serveurs, il va générer des scripts Python, à partir de fichiers yaml, qui seront exécutés en SSH sur les machines distantes.
C’est tellement simple qu’il n’y a rien à installer sur les serveurs s’ils respectent ces deux règles :
- Ils doivent être accessibles en SSH
- Python doit être installé (Il est installé par défaut dans la quasi-totalité des distributions Linux)
Ansible propose des modules qui couvrent une grande partie des commandes exécutées sur un serveur : installer un paquet, écrire un fichier, redémarrer un service… etc.
Cet article va expliquer et illustrer les différents concepts d’Ansible à travers la mise en place d’un scénario simple pour installer un environnement LAMP (Linux, Apache, MySQL et PHP).
Un projet Ansible est composé de plusieurs concepts, mais ne vous inquiétez pas, c’est bien organisé, chacun a un dossier à son nom.
Qu’est ce qu’un module Ansible ?
Commençons par la base : un module Ansible correspond à une fonction Python avec des paramètres en entrée qui sera exécutée sur les serveurs distants.
Ansible propose un grand nombre de modules qui pourront être utilisés pour réaliser vos actions (il est aussi possible d’écrire ses propres modules en Python).
Pour utiliser un module, nous allons écrire dans un fichier YAML le nom du module et la valeur des paramètres d’entrée disponibles (ils ne sont pas tous obligatoires).
Prenons un exemple simple : le module package permet d’installer un package système indépendamment du gestionnaire de paquet. C’est magique : Ansible choisira le gestionnaire de paquet en fonction de l’OS.
Le module package est utilisé ci-dessous pour installer le package ntpdate sur les machines distantes.
- name: install ntpdate
package:
name: ntpdate
state: present
Nous ne nous attarderons pas sur l’option state, mais comme certains l’auront sûrement deviné, il existe l’état “absent” qui supprime le package.
Appeler plusieurs modules grâce aux tasks
Maintenant que nous avons vu comment appeler un module, nous aimerions en appeler plusieurs. Pour cela nous allons définir une task qui est une liste de modules Ansible qui seront appelés de manière séquentielle.
Pour réaliser notre task permettant l’installation du service ntp, nous utiliserons trois modules.
En premier, nous appellerons le module package pour installer le package ntpdate, ensuite nous choisirons le module template pour écrire la configuration et pour terminer le module service qui nous permettra de le redémarrer.
Il faut voir une task comme une procédure atomique qui pourrait être réutilisée dans un autre projet.
-name: be sure ntp is installed
package:
name: ntp
state: present
- name: be sure ntp is configured
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify:
- restart ntpd
- name: be sure ntpd is running and enabled
service:
name: ntpd
state: started
enabled: yes
Organiser plusieurs tasks et leurs dépendances dans un rôle
Un rôle permet de regrouper les procédures d’une étape avec leurs dépendances :
Les tasks, les handlers, les templates, les variables et les fichiers utilisés par les tasks.
Dans l’exemple précédent, nous avions une task pour installer le service ntpdate, un template, des variables pour écrire le fichier de configuration du service et un handler pour redémarrer le service afin de prendre en compte le nouveau fichier de configuration. Tout ceci constituera notre premier rôle ntpdate.
Pour simplifier l’écriture des fichiers de configuration, Ansible propose l’utilisation de template au format jinja2.
Appliquons nos rôles grâce aux playbooks
Dans l’étape précédente, nous avons créé le rôle ntpdate, en plus de ce rôle nous avons besoin de deux rôles supplémentaires que nous appellerons httpd et mysql et qui vont reprendre la même structure que notre précédent rôle.
Maintenant que nous avons défini nos trois rôles (ntpdate, httpd et mysql), il est temps d’écrire notre scénario : le playbook.
Le playbook va définir dans quel ordre les rôles seront joués et sur quels serveurs.
Notons que les playbooks peuvent exécuter une liste de rôles ou directement une liste de tasks.
Dans notre scénario, le playbook exécutera sur toutes les machines les rôles ntpdate, httpd puis mysql :
hosts: all
roles:
- ntpdate
- httpd
- mysql
Les inventaires
Nous sommes presque prêts pour jouer nos scénarios, il ne manque que la liste des salles … euh des serveurs : c’est l’inventaire.
Les inventaires sont des fichiers ini qui permettent de nommer un serveur en associant son IP et son nom. Ces serveurs pourront être organisés en groupes de serveurs pour pouvoir installer plusieurs serveurs en même temps.
La bonne pratique est d’avoir un inventaire par environnement (un pour le dev et un pour la prod).
Fichier dev.ini
# un serveur nommer docker-farm-test
docker-farm-test
ansible_ssh_port=22
ansible_user=ansible
ansible_ssh_host=127.0.0.1
# le groupe de serveurs farms
[farms]
docker-farm-test
docker-farm-prod
# un groupe de plusieurs groupes
[allgroups:children]
farms
another-group
Pour appliquer le playbook sur les serveurs de l’inventaire dev.ini il faut utiliser l’option -i
$ ansible-playbook playbooks/playbook.yml -i dev.ini [options]
Les variables
Lors des premières répétitions, nous avons rencontré des problèmes, les serveurs n’étant pas les mêmes, il faudrait pouvoir adapter le scénario à chacun d’eux, quitte à couper du texte…
C’est là que rentre en jeu les variables, qu’elles soient de group ou de host, elles feront de chaque installation un moment unique en remplaçant les variables utilisées dans les rôles.
Ces variables seront surchargées en commençant par les : group_vars puis par les host_vars, par ordre alphabétique des fichiers.
Derniers conseils
Voici quelques conseils pour que votre première représentation soit un succès :
D’abord commencez par des scènes faciles, les modules de la collection builtin sont simples.
Si vous avez le trac : lisez la documentation, chaque module est fourni avec un exemple.
Ensuite ne négligez pas les répétitions : une fois un module m’a supprimé le contenu d’un dossier, heureusement qu’en rejouant le scénario j’ai pu le retrouver.
Finalement, avant de monter sur scène, votre rôle à besoin de ses variables. Regroupez les dans un fichier qui porte son nom pour que vous puissiez les retrouver facilement.
Je n’aime vraiment pas le YAML, y a-t-il une autre solution ?
Ansible a deux principaux concurrents : Chef et Puppet.
Puppet devrait vous convenir, il utilise un langage dédié (DSL – Domain-Specific Language) et des classes, l’équivalent de nos rôles pour Ansible, qu’il faudra ensuite appeler comme dans un programme classique.
Mais attention, Puppet fonctionne en mode client/serveur, il faudra donc au préalable installer sur chacun de vos serveurs un agent.
Liens utiles
- Instruction d’installation d’Ansible et ansible-playbook sur linux
https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#selecting-an-ansible-artifact-and-version-to-install - Liste des modules proposés par Ansible
https://docs.ansible.com/ansible/latest/collections/index.html - Le projet Ansible complet pour installer un environnement LAMP
https://github.com/ansible/ansible-examples/tree/master/lamp_simple
Côme Burguburu
Stéphane ROBERT
Merci pour cet article