Lab 11.2 : Déployer et mettre à l'échelle des services¶
| Durée | 75 min |
| Niveau | Semi-guidé |
| Prérequis | Lab 11.1 : Créer un cluster Swarm (cluster de trois nœuds en état), Lab 4.1 : Publier sur Docker Hub, cours du chapitre 11 |
| Acquis visés | AA8 |
!!! abstract "Objectifs" - Constater qu'une image doit être accessible par tous les nœuds, et la publier sur Docker Hub - Déployer un service répliqué et observer le placement des tâches - Vérifier le routing mesh et la répartition de charge - Mettre un service à l'échelle et observer l'auto-guérison - Déployer un service global - Mettre un nœud en maintenance sans interrompre le service
Contexte et schéma¶
Vous déployez une petite application qui répond par le nom du conteneur qui a traité la requête : en la sollicitant plusieurs fois, vous voyez quelle tâche répond. Les commandes docker service ... et docker node ... s'exécutent sur swarm-manager. Dans ce lab, seules les commandes clés vous sont données : à vous de les adapter et de déduire le reste à l'aide du cours.
flowchart LR
C["Client"] --> R["Routing mesh<br/>port 8080 sur chaque nœud"]
R --> T1["Tâche 1<br/>nœud A"]
R --> T2["Tâche 2<br/>nœud B"]
R --> T3["Tâche 3<br/>nœud C"]
H[("Docker Hub<br/>image publiée")] -. "téléchargement par chaque nœud" .-> T1
H -.-> T2
H -.-> T3
Organisation du travail
Ouvrez trois terminaux (un par VM) comme au Lab 11.1. Les tests curl se font depuis un terminal de VM Linux, avec l'adresse IP d'un nœud (relevée au Lab 11.1).
Étapes¶
Étape 1 : Préparer l'application¶
- Objectif : disposer d'une image qui affiche le nom du conteneur.
- Indices : sur
swarm-manager, créez un dossierqui-repondavec les trois fichiers suivants.
requirements.txt
app.py
import socket
from flask import Flask
app = Flask(__name__)
@app.route("/")
def accueil():
return f"Réponse du conteneur {socket.gethostname()}\n"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Dockerfile
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
Construisez l'image qui-repond:1.0 et vérifiez-la avec un conteneur isolé (docker run, curl), puis supprimez ce conteneur.
Pourquoi le nom d'hôte ?
Le nom d'hôte d'un conteneur est son identifiant court : il est différent pour chaque tâche. C'est ce qui permet de savoir laquelle a répondu.
!!! success "Point de contrôle" - [ ] curl affiche Réponse du conteneur ... avec un identifiant - [ ] Le conteneur d'essai est supprimé
Étape 2 : Constater la limite d'une image locale¶
- Objectif : comprendre pourquoi l'image doit être dans un registre (section 4.3 du cours).
- Indices :
- Créez un service
test-localde 3 répliques avec l'image localequi-repond:1.0(non publiée), port 8081 de l'hôte vers le port 5000. - Lisez les messages affichés à la création, puis observez
docker service ps test-local --no-truncpendant quelques secondes : sur quels nœuds les tâches démarrent-elles, sur lesquels échouent-elles, avec quel message ? - Supprimez le service.
!!! success "Point de contrôle" - [ ] Vous avez relevé le message affiché à la création du service - [ ] Vous avez relevé ce qui se passe sur les workers (état et message d'erreur) - [ ] Vous savez expliquer pourquoi ce n'est pas le cas sur le manager
Étape 3 : Publier l'image sur Docker Hub¶
- Objectif : rendre l'image accessible par tous les nœuds.
- Indices :
- Connectez-vous à Docker Hub avec votre jeton d'accès (Lab 4.1), nommez l'image
<utilisateur>/qui-repond:1.0(docker tag) et publiez-la (docker push). - Vérifiez sur le site de Docker Hub que le dépôt est public : les workers téléchargeront l'image sans identifiants.
!!! success "Point de contrôle" - [ ] L'image est visible sur Docker Hub, dépôt public - [ ] Vous n'avez saisi aucun mot de passe dans vos fichiers ni dans un historique partagé
Étape 4 : Déployer un service répliqué¶
- Objectif : créer un service de 3 répliques et observer le placement.
- Indices :
- Créez le service
web: 3 répliques, port 8080 de l'hôte vers le port 5000, image<utilisateur>/qui-repond:1.0. - Observez :
docker service ls,docker service ps web,docker service inspect --pretty web. - Sur chaque nœud,
docker ps: quel conteneur y tourne ?
!!! success "Point de contrôle" - [ ] docker service ls affiche web avec 3/3 répliques - [ ] docker service ps web montre les trois tâches et leurs nœuds - [ ] Vous avez relevé la répartition des tâches sur les nœuds
Étape 5 : Vérifier le routing mesh¶
- Objectif : constater la répartition de charge et l'accès par n'importe quel nœud.
- Indices :
- Envoyez 12 requêtes à l'adresse du manager, puis comptez les réponses par conteneur :
- Recommencez avec l'adresse d'un worker.
- Réduisez le service à **2 répliques** (`docker service scale web=2`), repérez le nœud qui n'a plus de tâche, et envoyez-lui des requêtes.
!!! success "Point de contrôle" - [ ] Les requêtes sont réparties entre les conteneurs (plusieurs identifiants différents) - [ ] Le service répond aussi sur l'adresse d'un worker - [ ] Le nœud sans tâche répond quand même : vous savez l'expliquer par le routing mesh
Étape 6 : Mettre à l'échelle¶
- Objectif : changer le nombre de répliques sans interruption.
- Indices :
- Passez à 6 répliques, observez
docker service ps web, puis refaites l'envoi de 12 requêtes avec le comptage : combien de conteneurs différents répondent ? - Passez à 1 réplique, puis revenez à 3.
!!! success "Point de contrôle" - [ ] Avec 6 répliques, jusqu'à 6 conteneurs différents répondent - [ ] Vous avez observé la répartition des nouvelles tâches sur les nœuds - [ ] Le service est de nouveau à 3 répliques
Étape 7 : Observer l'auto-guérison¶
- Objectif : voir Swarm remplacer une tâche disparue.
- Indices :
- Sur un worker qui héberge une tâche, supprimez son conteneur à la main :
docker pspour repérer le conteneur, puisdocker rm -f. - Sur le manager, observez immédiatement
docker service ps webpuisdocker service ls.
!!! success "Point de contrôle" - [ ] L'ancienne tâche apparaît à l'état Failed ou Shutdown - [ ] Une nouvelle tâche est créée et passe Running - [ ] docker service ls revient à 3/3
Étape 8 : Déployer un service global¶
- Objectif : exécuter une tâche sur chaque nœud.
- Indices :
- Créez un service
agenten mode global avec l'imagealpine:3.20qui exécutesleep 3600. - Observez
docker service ps agent: combien de tâches, sur quels nœuds ? - Comparez avec le service
web.
!!! success "Point de contrôle" - [ ] Une tâche exactement par nœud - [ ] Vous savez expliquer la différence entre un service répliqué et un service global
Étape 9 : Mettre un nœud en maintenance¶
- Objectif : vider un nœud sans interrompre le service.
- Indices :
- Dans un terminal, lancez une boucle de requêtes continue vers le service (par exemple une requête par seconde pendant 2 minutes).
- Dans un autre, mettez
swarm-worker1endrain(section 7 du cours), puis observezdocker service ps web,docker service ps agentetdocker node ls. - Remettez le nœud en
active: reçoit-il de nouveau des tâches deweb? Que se passe-t-il pour le service global ? - Pour rééquilibrer, réduisez puis rétablissez le nombre de répliques de
web.
!!! success "Point de contrôle" - [ ] Le service a continué de répondre pendant le drain - [ ] Les tâches de web ont été recréées sur les autres nœuds - [ ] Après active, le nœud ne reprend pas automatiquement ses anciennes tâches - [ ] Après réduction puis rétablissement des répliques, les tâches sont de nouveau réparties
Étape 10 (facultative) : Panne d'un nœud¶
- Objectif : observer la réaction du cluster à la perte d'une machine.
- Indices :
- Sur
swarm-worker2, arrêtez le moteur Docker (sudo systemctl stop docker.service docker.socket) ou éteignez la VM. - Sur le manager, observez
docker node lsetdocker service ps webpendant une minute : après combien de temps les tâches de ce nœud sont-elles recréées ailleurs ? - Redémarrez le nœud et observez son retour.
!!! success "Point de contrôle" - [ ] Le nœud passe Down - [ ] Les tâches de web sont recréées sur les nœuds restants - [ ] Le service reste accessible pendant la panne
Étape 11 : Dresser la fiche de commandes¶
- Objectif : retenir les commandes de pilotage d'un service.
- Indices : complétez le tableau avec la commande que vous avez utilisée.
| Besoin | Commande |
|---|---|
| Lister les services | |
| Voir où tournent les tâches | |
| Changer le nombre de répliques | |
| Voir la configuration d'un service | |
| Mettre un nœud en maintenance | |
| Remettre un nœud en service |
!!! success "Point de contrôle" - [ ] Chaque ligne contient une commande que vous avez exécutée
Questions de réflexion¶
Pourquoi le service créé avec l'image locale pose-t-il problème sur les workers ?
Chaque nœud télécharge lui-même l'image qu'on lui demande d'exécuter. L'image construite sur le manager n'existe pas sur les workers et n'est pas dans un registre : ils ne peuvent pas la télécharger.
Pourquoi un nœud qui n'exécute aucune tâche répond-il quand même sur le port publié ?
Grâce au routing mesh : le port est ouvert sur tous les nœuds et les requêtes sont transmises à une tâche du service, où qu'elle se trouve.
Quelle différence entre supprimer un conteneur à la main et réduire le nombre de répliques ?
Supprimer un conteneur à la main change l'état réel sans changer l'état désiré : Swarm recrée le conteneur. Réduire le nombre de répliques change l'état désiré : Swarm supprime des tâches pour s'y conformer.
Pourquoi un nœud remis en active ne reprend-il pas ses anciennes tâches ?
Swarm ne rééquilibre pas les tâches existantes : un nœud ne reçoit que de nouvelles tâches. Une modification du nombre de répliques peut redistribuer la charge.
Dépannage¶
| Symptôme | Pistes |
|---|---|
docker service ps web : tâches Rejected ou Failed avec une erreur de téléchargement |
L'image n'est pas accessible aux nœuds : dépôt privé, nom incorrect ou pas de connexion Internet sur le worker |
Service à 0/3 |
docker service ps web --no-trunc pour lire le message d'erreur ; vérifiez le nom et le tag de l'image |
curl ne répond pas sur un nœud |
Port 8080 déjà utilisé sur ce nœud, ports du cluster bloqués (4789/udp), ou tâche encore en Preparing |
| Toutes les requêtes reviennent au même conteneur | Vérifiez que le service a plusieurs répliques Running ; attendez la fin du démarrage |
port is already allocated ou port already in use |
Un autre service ou conteneur occupe le port : changez le port publié |
Le nœud mis en drain garde ses tâches |
Attendez quelques secondes et relisez docker service ps ; vérifiez la commande de mise à jour de la disponibilité |
This node is not a swarm manager |
Vous êtes sur un worker : utilisez le manager |
Nettoyage et reprise¶
Supprimez les services, conservez le cluster :
Remettez tous les nœuds en active (docker node ls). L'image publiée sur Docker Hub reste disponible pour les prochains labs. Le Lab 12.1 utilise le même cluster.
Retour au chapitre¶
Chapitre 11 : Swarm : cluster et services · Quiz : Quiz du chapitre 11