Mai

Nous sommes souvent amenés à installer plusieurs serveurs avec la même configuration pour avoir des environnements de développement de recette et de production.

C’est une tâche longue et répétitive qui prend la forme d’un script ou d’un readme et vous n’êtes jamais à l’abri d’oublier de changer la configuration d’un serveur.

Ansible est la solution qui permet d’installer et de configurer une liste de serveurs à partir d’instructions simplifiées au format yaml.

Une simple commande appliquera vos modifications à plusieurs serveurs en même temps.

Présentation

Ansible permet d’installer des serveurs, il va générer des scripts Python, à partir d’un fichier yaml, qui seront exécutés en SSH sur les machines distantes.

Ansible est sans agent, les machines distantes doivent être accessibles en SSH et avoir Python installé, ce qui est le cas de toutes les 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…

Cet article va expliquer et illustrer les différents concepts d’Ansible à travers la mise en place d’un environnement LAMP (Linux, Apache, MySQL, PHP).

Le projet utilisé pour illustrer ces concepts est disponible ici ansible-examples/lamp_simple at master · ansible/ansible-examples

Un projet Ansible est composé de plusieurs concepts, chacun réparti dans un dossier bien distinct.

Qu’est ce qu’un module Ansible ?

Un module Ansible est 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 possible d’écrire ses propres modules en Python).

Ils sont listés ici : https://docs.ansible.com/ansible/latest/modules/modules_by_category.html

On n’écrit pas de script Python pour appeler un module Ansible, on écrit son nom suivi de ses paramètres dans un fichier au format YAML.

Le module package permet d’installer un package système indépendamment du gestionnaire de paquet (Ansible choisira le gestionnaire de paquet en fonction de la famille 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

 

Qu’est ce que l’option state ?

Certains modules (file, package, cron) utilisent l’option state qui peut prendre deux valeurs :

  • present : ajoute s’il n’existe pas.
  • absent : supprime s’il existe à partir du nom du package ou du chemin du fichier

Si on définit l’option state à “absent” dans l’appel du module package, le package ntpdate sera désinstallé.

Appeler plusieurs modules grâce aux tasks

Pour exécuter plusieurs modules à la suite on va définir une task qui est donc une liste de modules Ansible qui seront appelés de manière séquentielle.

Une task pour installer un service permet d’installer le package, d’écrire la configuration et de redémarrer le service en appelant les trois modules correspondants (package, template et service).

Il faut voir une task comme une procédure atomique qui pourrait être réutilisée dans un autre projet.

La task ntpdate va installer, configurer puis démarrer le service ntp.

fichier: roles/ntp/tasks/main.yml

- 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.

Si on reprend l’exemple précédent, on a 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.

Pour simplifier l’écriture des fichiers de configuration, Ansible propose l’utilisation de template au format jinja2.

fichier: roles/ntp/templates/ntp.conf.j2

driftfile /var/lib/ntp/drift

restrict 127.0.0.1=20

restrict -6 ::1

server {{ ntpserver }}

keys /etc/ntp/keys

 

Dans ce template, on utilise une variable ntpserver entre double accolade.

Elle sera déclarée dans le dossier vars et injectée dans le template lorsque le rôle sera joué.

fichier: roles/ntp/vars/ntp.yml

ntpserver: 192.168.1.2

 

Pour finir, un handler permet de déclencher une action, par exemple le redémarrage du service.

fichier roles/ntp/handlers/main.yml

- name: restart ntp

  service:

    name: ntpd

    state: restarted

 

Appliquons nos rôles grâce aux Playbooks

On a maintenant plusieurs rôles : un pour chaque élément de la stack Apache, PHP, MySQL : ntpdate, httpd et mysql.

Pour les appliquer, on utilise un playbook qui va lister dans l’ordre les rôles à jouer.

Notons que les playbooks peuvent exécuter une liste de rôles ou directement une liste de tasks.

Le playbook exécute sur toutes les machines les rôles ntp, httpd puis mysql :

fichier : playbooks/site.yml

hosts: all

roles:

  - ntpdate

  - httpd

  - mysql

 

Les inventaires

Maintenant que l’on a un playbook et des rôles pour installer notre stack php-mysql, il ne reste plus qu’à définir une liste de serveurs grâce aux inventaires (un pour le dev et un pour la prod).

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. 

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

On a vu comment nommer et grouper les serveurs cibles, il est possible d’ajuster les variables pour un serveur ou un groupe de serveurs.

Ces variables de groupe remplaceront les variables utilisées dans les rôles.

Les group_vars permettent de définir des variables pour un groupe.

De même, host_vars permet de définir une variable pour un seul serveur.

Les variables seront surchargées en commençant par les : group_vars puis par les host_vars, par ordre alphabétique des fichiers.

Bonnes pratiques

L’organisation d’un projet Ansible est très importante. Quelques recommandations pour s’y retrouver :

  • Utilisez un dossier playbooks pour stocker vos playbooks.
  • Nommez vos fichiers de variables des group_vars avec le même nom que les rôles les utilisant.
  • Nommez avec l’instruction name tous vos rôles et tasks.

Si vous utilisez un rôle (surtout si vous ne l’avez pas écrit), lisez les tasks pour être sûr de l’utilisation des variables et de ses effets de bords (suppression du dossier en amont).

Pour aller plus loin

Ansible est un outil puissant qui simplifie l’évolution des infrastructures.

On commence souvent par des cas simples d’installation de paquets, puis avec de la pratique, on apprend à cloner des repositories Git, déployer des clés SSH et configurer des crons.

La documentation d’Ansible définit pour chaque module la liste des paramètres disponibles et donne un exemple que vous pourrez adapter à votre usage.

Des paramètres avancés permettent d’utiliser des boucles, des variables de type objet et un mode debug que nous détaillerons lors d’un prochain article.

Installation d’Ansible

  • Instruction d’installation d’ansible et ansible-playbook sur linux.

https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html#selecting-an-ansible-version-to-install

 

Côme Burguburu

Related Posts

Leave A Comment