Mettre en place un serveur Web avec Ansible: tuto de présentation

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.

structure d’Ansible

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
première exécution du playbook

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.

exécution du playbook avec une boucle

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
exécution du playbook avec ajout d’un user pour utiliser des variables

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();
?>
modules : file template command copy handlers
modules : file template command copy handlers , suite …

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.

test sur le navigateur si les deux noms de domaines fonctionnent

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

4 thoughts on “Mettre en place un serveur Web avec Ansible: tuto de présentation

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

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

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

    1. Bonjour,
      Il faut utiliser le protocol SFTP et vérifier que le port SSH est correct (port 22 par défaut).

Comments are closed.