Mettre à jour un hôte à la fois

AnsibleBeginner
Pratiquer maintenant

Introduction

Le site de Courtyard Sessions fonctionne sur deux serveurs. Le nouveau programme est prêt, mais une mise à jour simultanée pourrait laisser les visiteurs sans site disponible. Utilisez Ansible pour examiner l’état réel et publier le nouveau paquet sur un serveur à la fois.

Vous devez savoir vous déplacer dans un terminal et avoir pratiqué un petit inventaire Ansible, les variables et les tâches file/copy. La passerelle, l’accès SSH et les paquets sont prêts. Ce laboratoire explique le lieu d’exécution, la délégation, les lots, les liens de version et les vérifications HTTP complètes avant leur utilisation. La durée est une estimation de l’auteur incluant lecture et corrections courantes.

Comprendre où chaque tâche s’exécute

Dans cette étape, vous allez créer un playbook d’inspection en lecture seule qui montre la version exécutée sur chaque serveur et le pool de routage réellement actif.

Le site destiné aux visiteurs de Courtyard Sessions fonctionne déjà. Ouvrez l’onglet Website. Lisez Good things, around the corner., puis cliquez sur The program. La page défile jusqu’aux deux séances, dont la première est Coffee in the courtyard. Cliquez sur Download the program (CSV) et ouvrez le fichier téléchargé : son en-tête est time,session,place, suivi des deux séances affichées. Un CSV est un tableau en texte brut dont les champs sont séparés par des virgules. Ce vrai téléchargement doit rester utilisable pendant la mise à jour.

La passerelle distribue les requêtes HTTP courtes entre deux serveurs. Retirer un serveur du pool actif empêche l’envoi de nouvelles requêtes de la passerelle vers ce serveur ; l’ajouter le remet dans la rotation. Cette petite passerelle préparée ne draine pas les connexions longues et ne reproduit pas une plateforme complète de publication dans le cloud. Les deux serveurs sont des conteneurs gérés par SSH partageant le noyau de cette VM de formation. Le contrôleur est la machine qui exécute Ansible et la passerelle.

Passez à l’onglet Controller. Il démarre dans /home/labex/project. pwd affiche le répertoire courant ; cat affiche un fichier :

pwd
cat inventory.yml
cat group_vars/all.yml

L’inventaire contient des données structurées compatibles avec YAML. Son groupe website contient web1 et web2, chacun avec son adresse réelle ansible_host et les paramètres SSH préparés. Le groupe control contient controller avec une connexion locale. Utilisez inventory.yml, choisi par le fichier ansible.cfg du projet ; le fichier initial inventory.ini de l’image n’est pas l’inventaire du cours.

Les variables de groupe fournissent backend_port (8090), pool_api réservé au contrôleur, le release_root autorisé, le package_root local et les identifiants de version. baseline_release vaut courtyard-preview ; approved_release vaut courtyard-weekend. Ce sont des noms de répertoires, pas des versions d’Ansible ou de logiciel. Un port HTTP identifie un service à l’écoute sur une adresse. /identity renvoie du JSON, un texte structuré identifiant la version réellement exécutée par le serveur. /pool renvoie la liste actuelle des nœuds actifs du contrôleur.

Si une commande affiche « No such file or directory », vérifiez l’orthographe avec ls, puis revenez avec cd /home/labex/project si nécessaire. Vous pouvez répéter une lecture sans risque. Conservez tous les fichiers des paquets, les données de connexion, les fichiers de la version originale et les notes privées de l’organisateur.

Par défaut, Ansible exécute une tâche par SSH sur chaque serveur sélectionné. Sur un serveur, 127.0.0.1 désigne ce serveur lui-même. delegate_to: controller exécute cette tâche particulière sur le contrôleur, dont le propre 127.0.0.1 héberge l’API du pool. La délégation ne change pas inventory_hostname : il désigne toujours le serveur en cours de gestion. Une requête du contrôleur peut ainsi cibler le bon serveur.

Créez inspect.yml. cat > filename écrit un fichier en remplaçant celui du même nom s’il existe. <<'YAML' commence un here-document : collez jusqu’au YAML final, seul sur sa ligne. Le délimiteur entre guillemets conserve littéralement le texte collé ; Ansible traite les expressions lors de l’exécution du playbook. L’indentation utilise des espaces. {{ variable }} insère une variable Ansible. gather_facts: false évite de collecter des informations machine sans rapport avec l’exercice.

Le module uri envoie une vraie requête HTTP ; sa méthode par défaut, GET, lit une ressource. register conserve son résultat réel sous un nom. Pour une réponse JSON, .json contient les champs analysés. debug affiche ces observations enregistrées ; il ne crée ni la version ni l’état du pool.

cat > inspect.yml <<'YAML'
- name: Inspect the running website without changing it
  hosts: website
  gather_facts: false
  tasks:
    - name: Read this backend on its own loopback address
      ansible.builtin.uri:
        url: "http://127.0.0.1:{{ backend_port }}/identity"
      register: backend
    - name: Read the pool on the controller
      ansible.builtin.uri:
        url: "{{ pool_api }}/pool"
      delegate_to: controller
      register: pool
    - name: Show the actual release and active pool
      ansible.builtin.debug:
        msg:
          node: "{{ inventory_hostname }}"
          release: "{{ backend.json.release }}"
          active: "{{ pool.json.active }}"
YAML

Exécutez le playbook. ansible-playbook lit les tâches et les applique à l’inventaire :

ansible-playbook inspect.yml

Chaque serveur doit afficher release: courtyard-preview, et active doit contenir web1 et web2. Le format et les adresses peuvent varier. Notez que le premier uri s’exécute sur le serveur, tandis que la lecture du pool affiche une délégation telle que web1 -> controller. Les deux tâches sont en lecture seule.

Si l’indentation YAML est incorrecte, recopiez le bloc complet pour corriger le fichier, puis réessayez. Ce playbook ne doit jamais copier de fichiers ni modifier le pool. Vous disposez maintenant d’un outil utile pour observer à nouveau l’état après la publication.

Publier sur un serveur à la fois

Dans cette étape, vous allez livrer le paquet web approuvé par SSH, vérifier son contenu réel pour les visiteurs et remettre chaque serveur en service avant de commencer le suivant.

Restez dans l’onglet Controller, dans /home/labex/project. Listez les paquets, puis lisez le programme approuvé. ls énumère les entrées d’un répertoire :

ls packages
cat packages/courtyard-weekend/schedule.csv

Le programme approuvé contient trois séances : Bread and stories, Acoustic afternoon et Print a postcard. Une page d’accueil correcte ne suffit pas : les visiteurs ont besoin du téléchargement complet correspondant. Le paquet courtyard-incomplete est réservé au laboratoire suivant ; sélectionnez ici courtyard-weekend, comme le fait déjà la variable release_id.

Votre playbook traite un lot d’un hôte avec serial: 1. Dans ce lot, il retire le nœud du pool, copie le paquet, bascule le lien de version active, vérifie les deux ressources métier et réintègre le nœud. Le lot suivant commence seulement ensuite. order: sorted fait démarrer la démonstration avec web1. any_errors_fatal: true propage explicitement un échec non traité pour arrêter le play. Dans ces lots d’un seul hôte, l’échec de cet hôte fait déjà échouer tout le lot. Ce réglage n’annule pas les tâches terminées. Le laboratoire suivant ajoute la récupération.

L’API du pool accepte un HTTP POST vers /pool avec un corps JSON : node désigne le nœud géré et enabled est le booléen false pour le retirer ou true pour l’ajouter. body_format: json sérialise correctement ce corps. Les tâches du pool s’exécutent sur le contrôleur ; les tâches de fichiers, sur le serveur SSH sélectionné.

file avec state: directory crée un répertoire ; le mode '0755' permet au propriétaire d’écrire et à tous de lire ou traverser le répertoire. copy envoie le paquet sélectionné du contrôleur vers ce serveur. Le / final de src copie son contenu, avec le mode '0644' pour des fichiers lisibles. file avec state: link crée ou modifie un lien symbolique : current pointe vers un répertoire de version. À chaque requête, le serveur HTTP préparé sert les vrais fichiers à travers ce lien. Basculer le lien change le site actif sans redémarrer le serveur et conserve le répertoire original intact.

Pour les sondes HTTP exécutées sur le contrôleur, hostvars[inventory_hostname].ansible_host obtient explicitement l’adresse du serveur géré. Pendant une délégation, une variable de connexion non qualifiée peut désigner l’hôte délégué. return_content: true enregistre le corps réel de la réponse dans .content.

assert exige que son expression that soit vraie. lookup('file', ...) lit le fichier attendu du paquet sur le contrôleur ; ~ concatène les chaînes du chemin. rstrip=False conserve les sauts de ligne finaux pour comparer le corps complet, pas un fragment tronqué. La page complète du candidat et le CSV approuvé complet doivent correspondre avant toute réintégration. Un 404 signifie que le serveur a répondu mais que la ressource manque ; une erreur de connexion signifie que le service est inaccessible. Aucun des deux ne désigne une version saine.

Écrivez le déploiement complet. Le here-document utilise la même méthode d’écriture que l’outil d’inspection :

cat > rollout.yml <<'YAML'
- name: Release one website backend at a time
  hosts: website
  order: sorted
  gather_facts: false
  serial: 1
  any_errors_fatal: true
  tasks:
    - name: Drain this backend from the pool
      ansible.builtin.uri:
        url: "{{ pool_api }}/pool"
        method: POST
        body_format: json
        body:
          node: "{{ inventory_hostname }}"
          enabled: false
      delegate_to: controller
    - name: Create this release directory
      ansible.builtin.file:
        path: "{{ release_root }}/releases/{{ release_id }}"
        state: directory
        mode: '0755'
    - name: Copy the selected package over SSH
      ansible.builtin.copy:
        src: "{{ package_root }}/{{ release_id }}/"
        dest: "{{ release_root }}/releases/{{ release_id }}/"
        mode: '0644'
    - name: Activate the selected release
      ansible.builtin.file:
        src: "{{ release_root }}/releases/{{ release_id }}"
        dest: "{{ release_root }}/current"
        state: link
    - name: Read the real candidate homepage
      ansible.builtin.uri:
        url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/"
        return_content: true
      delegate_to: controller
      register: homepage
    - name: Require the complete candidate homepage
      ansible.builtin.assert:
        that: homepage.content == lookup('file', package_root ~ '/' ~ release_id ~ '/index.html', rstrip=False)
    - name: Read the real candidate download
      ansible.builtin.uri:
        url: "http://{{ hostvars[inventory_hostname].ansible_host }}:{{ backend_port }}/schedule.csv"
        return_content: true
      delegate_to: controller
      register: download
    - name: Require the complete approved program
      ansible.builtin.assert:
        that: download.content == lookup('file', package_root ~ '/' ~ approved_release ~ '/schedule.csv', rstrip=False)
    - name: Rejoin only after both business checks
      ansible.builtin.uri:
        url: "{{ pool_api }}/pool"
        method: POST
        body_format: json
        body:
          node: "{{ inventory_hostname }}"
          enabled: true
      delegate_to: controller
YAML

Vérifiez d’abord le YAML et la structure des tâches sans déployer. --syntax-check valide la syntaxe, mais ne prouve pas le résultat métier :

ansible-playbook rollout.yml --syntax-check

Si la vérification signale une erreur d’orthographe ou d’indentation, recopiez le fichier complet et réessayez. Lancez ensuite le vrai déploiement :

ansible-playbook rollout.yml

Les tâches de web1 doivent finir avant celles de web2. Les deux hôtes doivent terminer avec failed=0 et unreachable=0. Les requêtes opérationnelles de retrait et de réintégration peuvent afficher ok ; leur réussite HTTP et leur effet réel comptent davantage que le compteur changed du récapitulatif. Si une erreur de modification interrompt l’exécution, corrigez le fichier complet et relancez le même paquet approuvé. Répéter ce flux retire, vérifie et réintègre à nouveau les nœuds ; ce n’est pas un déploiement sans opération.

Inspectez l’état avec votre outil initial :

ansible-playbook inspect.yml

Les deux nœuds doivent maintenant annoncer courtyard-weekend et être actifs dans le pool. Passez à Website et rechargez. Le titre doit être A little room for a good afternoon. Cliquez sur The program, vérifiez les trois séances, téléchargez de nouveau le CSV et ouvrez le nouveau fichier pour confirmer les trois lignes complètes. Le navigateur peut ajouter un numéro au nom si un téléchargement précédent existe. Plan a visit doit toujours mener aux informations d’accès sans marche par l’entrée du jardin.

Le programme mis à jour contient les trois séances approuvées ; le vrai téléchargement CSV se trouve à côté de la liste.

Site Courtyard Sessions mis à jour avec ses trois séances

Ces résultats démontrent une mise à jour fonctionnelle de deux nœuds dans l’environnement préparé de requêtes courtes. Ils n’établissent pas une garantie d’absence d’interruption pour tout trafic ou toute application en production.

Résumé

Vous avez créé un outil d’inspection en lecture seule et utilisé un déploiement Ansible séquentiel pour livrer un vrai site et le téléchargement complet de son programme. Les changements délégués du pool et les vérifications réelles relient chaque décision de publication au serveur géré concerné.