Tous droits réservés

Découverte d'Ansible par un nul

À l'occasion de la refonte de mon site/portfolio/blog je suis passé de GitHub Pages à un VPS… il a donc fallu configurer le serveur et automatiser le déploiement du code.

Attention

Cet article n’a pas vocation à être un tutoriel complet, ni même une référence : il s’agit ici de retracer ma première expérience avec Ansible.

Après des années à configurer les serveurs à la main, en me connectant en SSH à chaque fois (y compris sur des clusters de plusieurs machines similaires), il était temps d’apprendre à automatiser et paralléliser tout ça !

Ayant travaillé récemment sur AWS pour mettre en place l’infrastructure soutenant une application médicale, j’ai été tenté d’utiliser un service cloud, pour m’éviter toute maintenance. Mais garder un peu la main sur l’infra me paraît important pour ne pas devenir dépendant d’un service : va pour un VPS chez Gandi (des français que je respecte beaucoup, qui hébergent d’ailleurs gracieusement ZdS) !

Principes de base

De ce que j’en ai compris, l’idée d’Ansible est de fournir une liste d’actions reproductibles pour configurer, installer ou mettre à jour une machine.

Chaque action est une tâche (ex. : installer le package nginx ou copier un fichier de configuration).

Les tâches peuvent être regroupées en rôles pour configurer un même module (ex. : actions spécifiques à la mise en place de Nginx ou clonage du dépôt Git).

Les rôles peuvent contenir des gabarits (templates en anglais), des fichiers bruts et des gestionnaires (handlers en anglais).

Les tâches et les gabarits peuvent faire appel à des variables, les rendant ainsi adaptatifs et réutilisables.

Mise en route

Ansible fournit un guide d’installation assez fourni sur le sujet, mais comme la loi de Murphy l’a prédit : ce qui pouvait mal se passer s’est mal passé.

J’ai donc vite abandonné l’installation manuelle pour utiliser Homebrew : un rapide brew install ansible et le tour est joué ! Je peux confirmer que ça fonctionne avec ansible all -m ping --ask-pass pour être sûr… et c’est parti pour jouer avec ce nouvel outil.

Le principal avantage est qu’Ansible ne requiert pas de configuration spécifique sur le serveur, tant que Python y est installé (ce qui est le cas par défaut des principales distributions Linux).

Premiers essais

On commence par configurer nos hôtes. Par défaut Ansible va chercher le fichier /etc/ansible/hosts :

[portfolio]
portfolio_www ansible_host=www.corentin-hatte.eu ansible_user=corentin

Pour faire simple j’ai commencé par des actions simples, sans passer par un rôle :

---
- name: Mon premier test Ansible
  hosts: all
  tasks:
    - name: "Dis bonjour"
      command: "echo 'Hello World' > test.txt"

    - name: "Dis au revoir"
      command: "echo 'Goodbye World' > test.txt"

Et j’exécute mon fichier : ansible-playbook test.yml pour obtenir (si tout se passe bien) quelque chose comme ça :

PLAY [Mon premier test Ansible] ********************************************************************

TASK [Gathering Facts] *****************************************************************************
ok: [portfolio_www]

TASK [Dis bonjour] *********************************************************************************
changed: [portfolio_www]

TASK [Dis au revoir] *******************************************************************************
changed: [portfolio_www]

PLAY RECAP *****************************************************************************************
localhost                  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Les plugins : ça passe ou ça casse

Pour répondre à tous types de besoin, il est possible de créer des plugins Ansible, que l’on peut trouver sur Ansible Galaxy qui recense des contributions officielles et non-officielles installables par lots ou à l’unité.

L’avantage d’utiliser des plugins plutôt que d’exécuter des commandes à tout va, c’est qu’un plugin va aller vérifier l’état actuel de votre machine cible pour ne rien changer si tout est déjà bon. Ça évite des traitements inutiles et des erreurs potentielles.

J’en utilise quelques-uns sans problème. D’autres n’ont tout simplement pas fonctionné (comme ceux pour certbot que j’avais trouvés) pour mon besoin.

Le plugin MySQL… presque parfait ?

Le plugin MySQL officiel est très pratique pour les opérations de configuration de base de donnée, et fonctionne avec MariaDB également.

Je peux ainsi créer me base de données (avec son utilisateur dédié) facilement, sans risquer d’écraser quoi que ce soit :

- name: "Create MariaDB database"
  community.mysql.mysql_db:
    login_user: root
    login_password: "{{ mysql_root_password }}"
    name: "{{ db_name }}"
    state: present

- name: "Create MariaDB user"
  community.mysql.mysql_user:
    login_user: root
    login_password: "{{ mysql_root_password }}"
    name: "{{ db_user }}"
    password: "{{ db_password }}"
    priv: "{{ db_name }}.*:ALL"
    host: localhost
    state: present

Je me connecte ici en tant que root à MariaDB pour créer la base et l’utilisateur dont j’ai besoin, en utilisant les variables déclarées en amont.

Principale limitation : je n’ai pas encore trouvé de fonctionnalité pour générer une sauvegarde automatique. Il faudra sans doute passer par une commande plus manuelle…

J’ai également eu du mal à paramétrer le mot de passe root par défaut via ce plugin, je suis donc passé par une command pour ne pas perdre trop de temps.

Le plugin Composer… peut-être ?

En théorie ça a l’air très intéressant, mais du fait de ma configuration spécifique (avec un utilisateur www qui n’a que peu de droits) Ansible refuse d’exécuter les commandes à distance. Peut-être avez-vous des idées pour y parvenir ?

En attendant j’utilise un simple command: "sudo -u www composer update --no-scripts --no-dev" par exemple pour mettre à jour les dépendances…

Organiser ses fichiers

Dans mon dossier ansible, qui contient donc tout ma config de déploiement, j’ai l’architecture suivante :

  • roles/ (dossier regroupant les différents rôles et leurs définitions spécifiques)
  • group_vars/all (fichier contenant toutes les variables utilisées par les scripts)
  • .vault-password (fichier privé qui contient le mot de passe pour déchiffrer les mots de passes du coffre Ansible)
  • host (fichier de configuration Ansible d'inventaire des serveurs)
  • install.yml (fichier qui regroupe les rôles dédiés à la mise en place du serveur)
  • update.yml (fichier qui regroupe les rôles dédiés à la mise à jour du site)

Créer des rôles

Les rôles ont globalement la forme suivante (adaptée en fonction des besoins spécifiques :

  • tasks/main.yml (fichier décrivant les tâches à réaliser pour ce rôle)
  • files/fichier1.ext (fichier à copier tel quel sur le serveur)
  • templates/fichier1.ext (fichier utilisé comme template, dans lequel je peux injecter des variables Ansible avant de le copier sur le serveur)
  • handlers/main.yml (fichier d’écouteurs permettant de lancer des actions — comme relancer un service — en cas de notification)

En nommant les fichiers ainsi je n’ai pas à fournir beaucoup de configuration à Ansible : il sait directement où aller chercher ce dont il a besoin.

Mon rôle nginx est par exemple assez simple : on ajoute le dépôt officiel, on installe le paquet système et on copie la config.

---
- name: Add nginx stable repository from PPA and install its signing key on Ubuntu target
  ansible.builtin.apt_repository:
    repo: ppa:nginx/stable

- name: Install nginx
  apt:
    update_cache: yes
    name:
      - nginx

- name: Copy nginx configuration for Laravel
  template:
    src: portfolio.conf
    dest: /etc/nginx/sites-enabled/portfolio.conf
  notify: restart nginx

La dernière tâche notifie le gestionnaire qui se charge de s’assurer que le service Nginx est bien redémarré.

---
- name: restart nginx
  service:
    name: nginx
    state: restarted
    enabled: yes

Utiliser les rôles pour déployer tout ça

Avec le bon Makefile à la racine du projet je peux donc faciliter les déploiements :

server-create: server-install server-deploy

server-install:
	cd ansible && ansible-playbook -i hosts --vault-password-file .vault-password install.yml

server-deploy:
	cd ansible && ansible-playbook -i hosts --vault-password-file .vault-password update.yml

Le fichier update.yml qui décrit les rôles à utiliser pour mettre à jour le site ressemblant à ça :

---
- name: Deploy new website version
  hosts: all
  become: yes

  roles:
    - laravel
    - deploy

J’ai plus qu’à lancer un make server-deploy une fois le code poussé sur le dépôt Git et tout se fait automatiquement !


Maintenant que j’ai rédigé cet article j’ai plus qu’à tout reprendre pour améliorer… jamais satisfait. 🙃

1 commentaire

Petite note, vu qu’il s’agit d'une copie d’un article sur mon blog : j’ai depuis un peu fait évoluer mes méthodes, en ajoutant des tags par exemple pour n’exécuter que les tâches dont j’ai besoin.

Je suis toujours preneur de vos suggestions pour optimiser tout ça par contre, et pour faire fonctionner les plugins avec ma config d’utilisateurs qu’Ansible aime pas ^^

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte