Je vous présente un tutoriel d’introduction à Ansible qui est un logiciel pour automatiser le déploiement d’applications. L’installation d’Ansible est très simple et ne demande que python et SSH pour fonctionner. Par exemple, au lieu de taper un apt-get install ou un yum install en ligne de commande pour installer un programme, vous pouvez utiliser Ansible pour faire ça.
Dans ce tuto, je vous montre comment mettre en place un serveur web Apache automatiquement sans entrer de ligne de commande en SSH. En créant simplement un script (playbook) où une suite de commandes suffisent à installer et configurer un serveur web Apache. En plus, vous pourrez réutiliser ce script pour d’autres installations et également pour faire des installations simultanées sur plusieurs serveurs.
Structure d’Ansible pour ce tuto
Vous allez découvrir l’utilisation des modules, des boucles, des variables, des templates et des handlers. J’utilise trois serveurs. Le premier est un serveur Linux où est installé Ansible que j’ai nommé ns1358, et deux autres serveurs Linux où il y a uniquement un système de base d’installé dessus et que j’ai nommé respectivement ns1375 (adresse IP 81.28.96.252) et ns1378 (adresse IP 81.28.97.135). C’est sur ces deux derniers serveurs où je vais déployer automatiquement un serveur web Apache sur chacun d’eux.
Dans l’image ci-dessus, on a un fichier inventaire (Inventory) où l’on indique les machines que l’on veut utiliser sous le groupe [serveurweb], un script Yaml (Playbook) où seront lancé nos différentes commandes. Ici, le serveur Ansible enverra directement les commandes en SSH vers les deux serveurs, en utilisant des modules.
Pour éditer le playbook, je ne vais pas le faire directement un ligne de commande sur le serveur Ansible. Mais je vais utiliser l’éditeur Atom et le module Ftp-Remote, ce qui me permet d’éditer à distance (via SSH) les fichiers de ce tuto.
Écriture du fichier Inventory (hosts)
Sur le serveur Ansible, j’ai créé le dossier serveurweb et dans celui-ci, je crée le fichier hosts où je vais indiquer un groupe [serveurweb] avec les machines à utiliser. Ici, des adresses IP, mais je peux également indiquer des noms de machines comme avec le groupe [database], donné en exemple.
# /serveurweb/hosts [serveurweb] 81.28.96.252 81.28.97.135 [database] db1 db2
Écriture du Playbook
Maintenant, je crée le playbook, que je nomme install.yml. Il commence toujours par ---
et on commence également par documenter chaque action avec un – name: . Je lui indique ensuite le groupe que je vais utiliser, ici le groupe [serveurweb] avec la commande hosts: . Et avec quel user je veux travailler, ici pour le tuto, l’user root remote_user: .
--- - name: installation serveur web hosts: serverweb remote_user: root
Ensuite, je vais pouvoir ajouter les tâches avec la commande tasks: . Je vais lui indiquer d’installer Apache avec le module apt: en lui indiquant le nom du package apache2. Cela revient à faire un apt-get install apache2. Et toujours documenter chaque action avec – name: . J’en profite pour ajouter le package php.
tasks: - name: install apache apt: name=apache2 - name: install php apt: name=php
Sur le serveur Ansible (machine ns1538), je vais dans le dossier de travail cd /etc/ansible/serveurweb et je lance le playbook que je viens de créer, avec la commande ansible-playbook en indiquant avec l’option -i, quel fichier hosts (inventory) il faut utiliser et le nom du playbook (install.yml) à exécuter.
cd /etc/ansible/serveurweb ansible-playbook -i hosts install.yml
La tâche « Gathering facts », est une tâche lancée automatiquement par Ansible, et qui récupère beaucoup de données sur les serveurs cibles, comme le nom de la distribution, le kernel, la mémoire vive, etc … On peut ainsi définir des actions à faire en fonction de ces valeurs. Pour désactiver cette tâche, on peut indiquer dans le playbook gather_facts: no.
Les valeurs en jaune indiquent qu’une tâche a bien été effectuée. Elles restent en vert si l’action n’a pas besoin d’être de nouveau exécutée, par exemple si on relance le même playbook. À la fin, il y a un récapitulatif des actions effectuées ou non.
Utiliser des boucles
On peut voir dans le playbook, que, si je veux ajouter un package, je dois à chaque fois réutiliser le module apt: , ce qui n’est pas très pratique. Je peux utiliser, ici, une boucle avec l’argument with_items.
- name: install apache php apt: name={{ item }} with_items: - apache2 - php
Et, si je relance le playbook, je peux voir qu’il utilise bien la boucle. Le résultat reste en vert, car ces deux tâches ont déjà été faites sur les deux serveurs cibles. D’ailleurs, il va beaucoup plus vite.
Utiliser des variables
Je vais maintenant ajouter un utilisateur sur les deux machines cibles avec le module user: . Pour cela, j’ajoute l’user pierre et la tâche « ajout d’un user ». Pour récupérer la valeur de user (pierre), il faut l’indiquer comme cela {{ user }}. J’indique aucun mot de passe et pas d’accès bash.
vars: user: pierre tasks: - name: ajout user user: name={{ user }} password=! shell=/bin/false
On peut voir avec user: pierre, que cela n’est pas très pratique d’avoir une variable en dur dans un script. Car on ne pourra pas de le réutiliser. Ce que l’on peut faire, c’est de commenter ces deux lignes.
# vars: # user: pierre
Et, ajouter dans le fichier hosts (inventory), les variables et leurs valeurs à la suite des adresses IP des deux serveurs. Et j’exécute de nouveau le playbook, il m’a bien ajouté les deux users pour chacun des deux serveurs cibles (ils sont colorés en jaune).
[serverweb] 81.28.96.252 user=pierre 81.28.97.135 user=paul
Modules : file, template, command, copy et handlers
Maintenant, pour aller un plus vite je vais faire un copier/coller pour la suite du script. Le but avec ces lignes supplémentaires, c’est d’ajouter et de configurer le serveur web Apache avec un nom de domaine différent pour chacune des deux machines cibles.
Pour le fichier hosts (inventory), je lui indique le nom de domaine pour chaque user en réutilisant la variable user dans ce même nom.
81.28.96.252 user=pierre domain="{{ user }}".imingo.net 81.28.97.135 user=paul domain="{{ user }}".imingo.net
Pour le playbook, j’indique ces options :
« name: dossier user » : Créer un dossier avec le nom de domaine, la variable {{ domain }} sera configurée par la suite. Avec les droits de user et un chmod de 755.
« name: virtualhost » : Copie le fichier qui se trouve dans templates/virtualhost.conf vers /etc/apache2/sites-available/{{ domain }}.conf. Cela va permettre avec le module template d’ajouter des variables dans ce fichier pendant la copie et de pouvoir les réutiliser. Je vous donne ce fichier par la suite.
« name: a2ensite » : Ici, j’indique à Apache de valider le domaine, et creates permet de lui indiquer de créer le fichier s’il n’existe pas, et s’il existe, tu le laisses en place. Le notify: indique à Apache qu’il doit être relancé, c’est en fait relié à handlers: ‘relancer Apache’. Cela permet de ne relancer Apache qu’une seule fois pendant l’exécution du playbook, même s’il a reçu plusieurs demandes de restart.
« name: phpinfo » : Permet de copier un fichier du serveur Ansible vers une machine cible. Copie le fichier qui se trouve dans src/phpinfo,php vers /var/www/ avec les droits de {{ user }}. je vous donne ce fichier par la suite.
- name: dossier user file: path=/var/www/{{ domain }} state=directory owner={{ user }} group={{ user }} mode=0755 - name: virtualhost template: src=templates/virtualhost.conf dest=/etc/apache2/sites-available/{{ domain }}.conf - name: a2ensite command: a2ensite {{ domain }} args: creates: /etc/apache2/sites-enabled/{{ domain }}.conf notify: relancer Apache - name: phpinfo copy: src=files/phpinfo.php dest=/var/www/{{ domain }} owner={{ user }} group={{ user }} mode=0644 handlers: - name: relancer Apache service: name=apache2 state=reloaded
Et, les deux fichiers que j’ai utilisés avec le module template et copy.
serveurweb/templates/virtualhost.yml <VirtualHost *:80> ServerName {{ domain }} DocumentRoot /var/www/{{ domain }} ErrorLog ${APACHE_LOG_DIR}/{{ domain }}.error.log CustomLog ${APACHE_LOG_DIR}/{{ domain }}.access.log combined </VirtualHost> serveurweb/files/phpinfo.php <?php phpinfo(); ?>
Je vois qu’il a bien (en jaune) exécuté mes nouvelles tâches. Et qu’il a bien relancé le serveur web Apache avec le module handlers. Et quand je vérifie sur mon navigateur, j’ai bien les deux phpinfo qui fonctionnent sur mes deux serveurs cibles.
Les scripts vus dans cet article
Voilà, on a vu le déploiement simultané d’un serveur web sur deux serveurs Linux avec Ansible. Je vous mets, ci-dessous, tous les scripts vu dans cet article.
serveurweb/templates/virtualhost.yml <VirtualHost *:80> ServerName {{ domain }} DocumentRoot /var/www/{{ domain }} ErrorLog ${APACHE_LOG_DIR}/{{ domain }}.error.log CustomLog ${APACHE_LOG_DIR}/{{ domain }}.access.log combined </VirtualHost> serveurweb/files/phpinfo.php <?php phpinfo(); ?> serveurweb/hosts [serverweb] 81.28.96.252 user=pierre domain="{{ user }}".imingo.net 81.28.97.135 user=paul domain="{{ user }}".imingo.net serveurweb/install.yml --- - name: installation serveur web hosts: serveurweb remote_user: root tasks: - name: install apache php apt: name={{ item }} with_items: - apache2 - php - name: ajout d'un user user: name={{ user }} password=! shell=/bin/fasle - name: dossier user file: path=/var/www/{{ domain }} state=directory owner={{ user }} group={{ user }} mode=0755 - name: virtualhost template: src=templates/virtualhost.conf dest=/etc/apache2/sites-available/{{ domain }}.conf - name: a2ensite command: a2ensite {{ domain }} args: creates: /etc/apache2/sites-enabled/{{ domain }}.conf notify: relancer Apache - name: phpinfo copy: src=files/phpinfo.php dest=/var/www/{{ domain }} owner={{ user }} group={{ user }} mode=0644 handlers: - name: relancer Apache service: name=apache2 state=reloaded
Tuto très sympa pour se faire aux manip’, mais il y à de des fautes d’inattention qui n’aident pas du tout, sans compter le manque de guide quanta l’indentation capricieuse des yml.
Le groupe de machine s’appel [serverweb] mais l’appel est sur « serveurweb » = problème.
Le fichier de template est donné en « .conf » dans le playbook et écrit en « .yml » = problème.
L’indentation idéale se fait avec des couples de 2 espaces pour chaque niveau.
Ansible offre une vérification de syntaxe un peu plus claire que les erreurs basiques :
ansible-playbook –syntax-check fichier-playbook.yml
Merci pour le retour, je vais corriger cela pour les futurs lecteurs.
Exact pour le –syntax-check , et on peut également aller encore un peu plus loin en lançant un –check qui est équivalent à un dry-run. C’est-à-dire exécuter le playbook mais sans effectuer aucune modification. Mais cela peu renvoyer des erreurs si le playbook a besoin de valeurs modifiées pendant son exécution. Cependant, cela fait ressortir des erreurs que –syntax-check ne peut pas détecter.
Bonjour comment avoir un lien avec la vm hote car une fois que je lance le premier playbook, il me met déjà unreachable, j’ai bien installé le plugin ftp remote pour la com ssh?
Bonjour,
Il faut utiliser le protocol SFTP et vérifier que le port SSH est correct (port 22 par défaut).