Monthly Archives: November 2018

Ansible par la pratique – Troisième partie: Utilisation avancée de nos playbooks

Utilisation avancée de nos playbooks

Ce tutoriel est la suite de la première partie et de la deuxième partie consacrée à ansible.

L’intégralité des fichiers est versionné sur gitlab, en prenant le tag tuto-ansible-3. En effet la branche master va évoluer avec l’avancement de ce tutoriel.

Simple mise à jour du système

Il est possible de ne lancer qu’une partie de nos playbooks, en lui définissant des étiquettes et en les précisant à l’exécution.

En ajoutant juste la ligne “tags: update“, à la tâche “Ensure all pkgs are up-to-date“, on peut maintenant lancer un de nos playbooks pour faire les mises à jours (site ou system).

Alors oui, avant aussi on pouvait mettre notre VPS à jour, mais tout le playbook était exécuté, et le temps perdu était considérable.

Fichier roles/system/tasks/packages.yml
# System update
- name: Ensure all pkgs are up-to-date
  yum:
    name: '*'
    state: latest
  tags: update

...

On lance notre playbook en précisant l’étiquette à utiliser. Seules les tâches portant l’étiquette demandée (update) seront exécutées.

ansible-playbook -i staging --user root --tags update site.yml

A contrario, on peut aussi lancer l’intégralité de notre playbook, à l’exception des tâches portant l’étiquette précisée.

ansible-playbook -i staging --user root --skip-tags update site.yml

On peut, dans les deux cas précédant, préciser plusieurs étiquettes, en les séparant avec une virgule. Les guillemets sont là par sécurité.

ansible-playbook -i staging --user root --tags "update,vhosts" site.yml

Sauvegarde et restauration

En jouant habilement avec les étiquettes, on pourrait faire en sorte que notre playbook sauvegarde nos données et les restaure si besoin est.

Commençons par effectuer la sauvegarde. Concrètement, il n’y a pas grand chose à sauvegarder:

  • La base de données mariadb de wordpress.
  • Le répertoire wp-content/uploads qui contient les fichiers téléversés.

Comme le module ansible mysql_db permet de restaurer un fichier d’export compressé, on va économiser un peu notre bande passante en le compressant avant transfert sur notre poste.

On créé un nouveau fichier de tâche pour la sauvegarde: roles/blog/tasks/backup.yml.

  1. On exporte la base de données dans un fichier d’export à plat sur le VPS.
  2. On compresse le fichier d’export à plat sur le VPS.
  3. On créé des archives à partir des répertoires donnés en paramètres sur le VPS.
  4. On télécharge le fichier d’export compressé et les archives sur notre poste de travail, directement dans le répertoire files du rôle correspondant. Le chemin est relatif à notre fichier playbook, c’est à dire la racine de notre projet.
  5. On supprime le fichier d’export compressé et les archives sur le VPS.
Fichier roles/blog/tasks/backup.yml
- name: Dump database
  mysql_db:
    name: "{{ databases.wordpress.base }}"
    state: dump
    encoding: utf8
    target: "/tmp/{{ databases.wordpress.base }}.sql"
  tags: backup
  
- name: Compress dump database
  archive:
    path: "/tmp/{{ databases.wordpress.base }}.sql"
    dest: "/tmp/{{ databases.wordpress.base }}.sql.gz"
    remove: yes
  tags: backup
   
- name: Make tarballs from selected directories
  archive:
    path: "/usr/share/wordpress/wp-content/{{ item }}"
    dest: "/tmp/wp-{{ item }}.tar.gz"
  with_items:
    - "uploads"
  tags: backup
    
- name: Fetch database dump and tarballs
  fetch:
    src: "/tmp/{{ item }}"
    dest: "roles/blog/files/{{ item }}"
    flat: yes
  with_items:
    - "{{ databases.wordpress.base }}.sql.gz"
    - "wp-uploads.tar.gz"
  tags: backup

- name: Delete db dump and tarballs
  file:
    dest: "/tmp/{{ item }}"
    state: absent
  with_items:
    - "{{ databases.wordpress.base }}.sql.gz"
    - "wp-uploads.tar.gz"
  tags: backup

On modifie le fichier de tâche principal: roles/blog/tasks/main.yml.

On modifie la tâche nommée “Ensure database exists“, en lui ajoutant deux fonctions à exécuter (handlers) une fois la tâche exécutée (si la base existe, le statut est ok mais la tâche n’est pas effectuée). C’est à dire que si le playbook créé la base de données, il vérifiera la présence d’un fichier d’export et s’il est trouvé, il importera la base de données depuis ce fichier. Si la base existe déjà, la tâche ne fera absolument rien. De même si la base de données n’existe pas et que le fichier d’export n’existe pas, la base sera créée mais elle sera vide.

On ajoute une tâche de restauration de nos archives qui n’échoue jamais (failed_when: false), c’est à dire que l’erreur est ignorée si une des archive n’est pas trouvée, et le playbook continue. Sans cela l’exécution du playbook se serait arrêté net.

En ajoutant les étiquettes backup et never à notre tâche d’inclusion dans notre fichier de tâches principal, on pourra effectuer nos sauvegardes, seulement si l’étiquette backup est précisée à l’exécution du playbook. Alors oui, on peut aussi l’exécuter si on précise l’étiquette never, Mais c’est vraiment pas le but de cette étiquette spéciale définie par ansible.

Fichier roles/blog/tasks/main.yml
...
# Replace task "Ensure database exists"
- name: Ensure database exists and import dump
  mysql_db:
    name: "{{ databases.wordpress.base }}"
    state: present
    encoding: utf8
  notify:
    - Check if db dump exists
    - Import SQL databases
  tags:
    - restore
...
- name: Ensure wordpress is restored from backup
  unarchive:
    src: "{{ item }}.tar.gz"
    dest: "/usr/share/wordpress/wp-content"
    creates: "/usr/share/wordpress/wp-content/{{ item }}"
  with_items:
    - uploads
  tags:
    - restore
  failed_when: false
    
- name: Ensure some WordPress directories are owned by apache
...
# Just before EOF
- include_tasks: backup.yml
  tags:
    - never
    - backup

Et enfin notre fichier de fonctions déclenchées: roles/blog/handlers/main.yml

  • Vérifier que le fichier d’export de la base de données est présent sur le VPS
  • Importer la base de données que si et seulement si la vérification de la présence du fichier d’export a été exécutée et sa présence confirmée:
    1. la première fonction renseigne la variable dump_exists, parmi laquelle figure le résultat de l’existence du fichier : dump_exists.stat.exists. Autrement dit la variable dump_exists est définie, ainsi que la variable binaire dump_exists.stat.exists.
    2. le fichier d’export compressé de la base de données existe: c.a.d. la variable dump_exists.stat.exists est positive.
Fichier roles/blog/handlers/main.yml
- name: Check if db dump exists
  stat:
    path: "/tmp/{{ databases.wordpress.base }}.sql.gz"
  register: dump_exists

- name: Import SQL databases
  mysql_db:
    name: "{{ databases.wordpress.base }}"
    state: import
    encoding: utf8
    target: "/tmp/{{ databases.wordpress.base }}.sql.gz"
  when: dump_exists and dump_exists.stat.exists

Voilà, si le playbook doit créer la base de données, il importera le fichier d’export compressé, s’il existe.

Lancement du playboook

On lance maintenant un playbook qui supporte des options étiquettes.

Installation complète:

ansible-playbook -i staging --user root site.yml

Effectuer selulement la mise à jour du système:

ansible-playbook -i staging --user root --tags update site.yml

Effectuer la sauvegarde:

ansible-playbook -i staging --user root --tags backup site.yml

Effectuer juste la restauration, car on a mis des étiquettes là aussi:

ansible-playbook -i staging --user root --tags restore site.yml

Conclusion

Cette facilité à mettre le système à jour ou à faire et restaurer des sauvegardes permet de rester serein, même si à trois jours de vos vacances, votre hébergeur vous annonce qu’il arrête son service. Il suffit de faire la sauvegarde, d’en trouver un autre et de lancer le déploiement du nouveau système et retournez faire vos bagages, ansible s’occupe du reste.

Passage à Fedora 29

Le passage de Fedora 28 à Fedora 29 est passé comme une lettre à la poste et sans incident notable.

Comme d’habitude, il faut sauvegarder ses données au préalable et il peut être judicieux d’avoir à disposition un live CD ou clé , au cas où…

Montée de version

  1. On met à jour la version actuelle
    sudo dnf upgrade --refresh
  2. On installe le plugin dnf de montée de version
    sudo dnf install dnf-plugin-system-upgrade
  3. On initialise la montée de version, qui va:
    • ajouter les dépôts correspondants à la nouvelle version de Fedora
    • télécharger les paquets RPM (sans les installer)
    • tester la transaction d’installation
    sudo dnf system-upgrade download --releasever=29

    On peut ajouter l’option ‐‐allowerasing pour régler le problème de paquet non disponible pour la nouvelle version, de dépendances cassées ou de paquets retirés.

  4. Redémarrage et application de la montée de version
    sudo dnf system-upgrade reboot
  5. Le système va mettre à jour énormément de paquets et redémarrer (encore) une fois l’opération terminée.

Problèmes rencontrés

  • Les paquets provenant de mes dépôts COPR ne veulent plus se mettre à jour. Résolu en ré-initialisant les dépôts en questions:
    dnf copr enable tartare/netdata
    ...

    Mais je ne suis pas sûr que le problème n’était pas déjà présent.