Aller au contenu

Chapitre 12 : Swarm : stacks et exploitation

Objectifs du chapitre

  • Relier des services répartis sur plusieurs nœuds avec un réseau overlay
  • Déployer une application complète sous forme de stack à partir d'un fichier Compose
  • Fournir configurations et secrets aux services avec les objets de Swarm
  • Contrôler le placement des tâches
  • Mettre à jour un service progressivement et revenir en arrière en cas d'échec
  • Expliquer comment Swarm réagit aux pannes, et les limites des données locales
  • Situer Swarm par rapport à Kubernetes
  • Acquis d'apprentissage visé : AA8

1. Du service à la stack

Au chapitre 11, vous avez créé des services un par un avec docker service create. Une application réelle en comporte plusieurs (proxy, API, base de données), reliés par des réseaux, avec des secrets et des règles de mise à jour. Les créer à la main serait long et non reproductible, comme les docker run avant Compose.

Swarm reprend la solution de Compose : un fichier décrit l'application, et une stack est l'ensemble des services créés à partir de ce fichier.

flowchart LR
  F["compose.yaml<br/>services, réseaux, secrets, deploy"] -- "docker stack deploy" --> S
  subgraph S["Stack « app » dans le cluster"]
    P["Service app_proxy"]
    A["Service app_api"]
    D["Service app_db"]
  end

2. Les réseaux overlay

2.1 Principe

Sur une seule machine, un réseau bridge relie des conteneurs. Dans un cluster, les conteneurs d'un même service peuvent être sur des machines différentes : il faut un réseau qui s'étend sur plusieurs nœuds. C'est le rôle du pilote overlay. Il encapsule le trafic entre les nœuds, ce qui explique le port 4789/udp de l'annexe environnement.

flowchart LR
  subgraph N1["Nœud 1"]
    A1["api (tâche 1)"]
  end
  subgraph N2["Nœud 2"]
    D1["db"]
    A2["api (tâche 2)"]
  end
  A1 <-- "réseau overlay" --> D1
  A2 <--> D1

Les services d'un même réseau overlay se joignent par leur nom de service, comme dans un réseau bridge défini par l'utilisateur (chapitre 6), quel que soit le nœud qui les héberge.

docker network create --driver overlay reseau-app
docker service create --name db --network reseau-app ...
docker service create --name api --network reseau-app ...

Le réseau se crée sur un manager ; il n'existe sur un nœud que lorsqu'une tâche s'y connecte.

2.2 Résolution des noms et répartition de charge

Le nom d'un service est résolu vers une adresse virtuelle (VIP) unique, qui répartit les connexions entre les tâches du service. Un client interne n'a donc pas besoin de connaître le nombre de tâches ni leur emplacement. Le nom spécial tasks.<service> renvoie en revanche les adresses de toutes les tâches.

2.3 Chiffrement

Le trafic d'un réseau overlay entre les nœuds n'est pas chiffré par défaut. L'option --opt encrypted l'active :

docker network create --driver overlay --opt encrypted reseau-app

Le chiffrement ajoute un coût de traitement : on l'active quand le réseau entre les nœuds n'est pas de confiance.

3. Les stacks

3.1 Commandes

Commande Rôle
docker stack deploy -c compose.yaml app Crée ou met à jour la stack app (sur un manager)
docker stack ls Liste les stacks
docker stack services app Liste les services de la stack
docker stack ps app Liste les tâches de la stack
docker stack rm app Supprime la stack

La commande docker stack deploy sert aussi à mettre à jour : on modifie le fichier et on relance la même commande ; Swarm n'agit que sur ce qui a changé.

3.2 Nommage

Les objets créés sont préfixés par le nom de la stack : le service api de la stack app s'appelle app_api, et le réseau par défaut est app_default. Les services se joignent entre eux par leur nom court (api) au sein de la stack.

3.3 Ce qui change par rapport à Compose

Le fichier est celui que vous connaissez, avec une section supplémentaire deploy pour les paramètres propres à Swarm. Certaines clés de Compose ne s'appliquent pas à une stack :

Clé Compose Comportement avec docker stack deploy
build Ignorée : une stack utilise des images déjà construites et publiées dans un registre (chapitre 11)
depends_on Ignorée : Swarm ne gère pas l'ordre de démarrage ; l'application doit tolérer qu'un service soit un moment indisponible, et les healthchecks servent à détecter la disponibilité
container_name Ignorée : les tâches reçoivent des noms générés
restart Remplacée par deploy.restart_policy
mem_limit, cpus Remplacées par deploy.resources

Docker signale par un avertissement les options qu'il ignore.

3.4 La section deploy

Clé Rôle
replicas Nombre de tâches
mode replicated (par défaut) ou global
resources Limites (limits) et réservations (reservations) de processeur et de mémoire
restart_policy Quand et combien de fois redémarrer une tâche en échec
placement Contraintes de placement (section 5)
update_config Règles des mises à jour (section 6)
rollback_config Règles du retour arrière (section 6)

3.5 Un exemple de stack

services:
  proxy:
    image: nginx:1.27-alpine
    ports:
      - "8080:80"
    networks:
      - frontend
    deploy:
      replicas: 2

  api:
    image: utilisateur/api:1.0
    networks:
      - frontend
      - backend
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 128M
      restart_policy:
        condition: on-failure

  db:
    image: postgres:16-alpine
    networks:
      - backend
    deploy:
      replicas: 1

networks:
  frontend:
  backend:

Les deux réseaux sont créés avec le pilote overlay lors du déploiement de la stack. Remplacez utilisateur/api:1.0 par une image publiée et accessible à tous les nœuds.

Registre privé

Pour une image d'un registre privé, ajoutez l'option --with-registry-auth à docker stack deploy : les nœuds reçoivent les identifiants nécessaires pour télécharger l'image.

4. Configurations et secrets de Swarm

Swarm fournit deux objets pour injecter des données dans les tâches sans les mettre dans l'image ni dans des variables d'environnement (chapitre 10) :

Objet Contenu Stockage dans la tâche
Config Données non sensibles (fichier de configuration d'un serveur) Fichier monté dans le conteneur
Secret Données sensibles (mot de passe, clé) Fichier en mémoire, monté sous /run/secrets/<nom>

Les secrets sont chiffrés dans le cluster, transmis uniquement aux nœuds qui exécutent une tâche qui en a besoin, et montés en mémoire : ils ne sont pas écrits sur le disque du nœud.

4.1 Création

docker config create proxy_conf default.conf
printf 'motdepasse-tp' | docker secret create db_password -
docker config ls
docker secret ls

La commande docker secret create db_password - lit la valeur sur l'entrée standard (le tiret). docker secret inspect n'affiche jamais la valeur.

4.2 Utilisation dans une stack

services:
  proxy:
    image: nginx:1.27-alpine
    configs:
      - source: proxy_conf
        target: /etc/nginx/conf.d/default.conf

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

configs:
  proxy_conf:
    external: true

secrets:
  db_password:
    external: true

external: true indique que l'objet a déjà été créé avec docker config create ou docker secret create. On retrouve le même principe que le fichier /run/secrets/... du chapitre 10 avec POSTGRES_PASSWORD_FILE.

Configs et secrets sont immuables

On ne modifie pas un secret ou une config existants. Pour changer une valeur, on crée un nouvel objet (avec un autre nom, par exemple db_password_v2), on met la stack ou le service à jour pour l'utiliser, puis on supprime l'ancien. Le secret n'est pas non plus un coffre-fort : toute personne qui contrôle un manager ou le moteur Docker d'un nœud qui l'héberge peut le lire.

5. Contrôler le placement des tâches

Par défaut, Swarm répartit les tâches de façon équilibrée. On peut le contraindre avec deploy.placement.constraints :

deploy:
  placement:
    constraints:
      - node.role == worker
Contrainte Effet
node.role == worker Uniquement sur les workers
node.role == manager Uniquement sur les managers
node.hostname == swarm-worker1 Uniquement sur le nœud nommé
node.labels.zone == a Uniquement sur les nœuds portant l'étiquette zone=a

Les étiquettes se posent sur un nœud depuis un manager :

docker node update --label-add zone=a swarm-worker1

L'option max_replicas_per_node limite le nombre de tâches d'un service par nœud.

5.1 Les données et le placement

Un volume est local à un nœud

Un volume nommé (chapitre 5) est stocké sur un nœud. Si une tâche qui l'utilise est recréée sur un autre nœud, elle trouve un volume vide : les données restent sur l'ancien nœud. Pour un service avec données (base de données), il faut donc :

  • fixer la tâche sur un nœud précis avec une contrainte de placement, en acceptant que ce nœud soit un point de défaillance ; ou
  • utiliser un stockage partagé entre les nœuds, ou une base de données gérée hors du cluster.

Le choix d'un stockage partagé dépasse le cadre de ce cours : retenez que la réplication d'une base de données n'est pas résolue par le simple fait d'augmenter le nombre de répliques.

6. Mises à jour progressives et retour arrière

6.1 Principe

Mettre à jour un service ne doit pas l'interrompre. Swarm remplace les tâches par lots : il arrête quelques anciennes tâches, démarre les nouvelles, attend, puis passe au lot suivant.

flowchart LR
  A["3 tâches<br/>version 1.0"] --> B["1 tâche en 2.0<br/>2 tâches en 1.0"]
  B --> C["2 tâches en 2.0<br/>1 tâche en 1.0"]
  C --> D["3 tâches<br/>version 2.0"]
docker service update --image utilisateur/api:2.0 app_api

On peut aussi modifier la balise de l'image dans le fichier et relancer docker stack deploy.

6.2 Régler la mise à jour

Paramètre (update_config) Option de docker service update Effet
parallelism --update-parallelism Nombre de tâches remplacées à la fois
delay --update-delay Délai entre deux lots
order --update-order stop-first (arrêter l'ancienne avant de démarrer la nouvelle) ou start-first (démarrer la nouvelle avant)
failure_action --update-failure-action Que faire si la mise à jour échoue : pause, continue ou rollback
monitor --update-monitor Durée pendant laquelle une nouvelle tâche est surveillée avant de passer au lot suivant
deploy:
  replicas: 3
  update_config:
    parallelism: 1
    delay: 10s
    order: start-first
    failure_action: rollback

Avec start-first, il y a momentanément plus de tâches que de répliques voulues, mais le service ne descend jamais sous sa capacité : c'est le choix à privilégier pour un service sans interruption, quand l'application tolère deux versions simultanées.

Le healthcheck rend la mise à jour sûre

Quand l'image définit un healthcheck, Swarm attend qu'une nouvelle tâche soit healthy avant de continuer. Sans healthcheck, il considère la tâche comme prête dès qu'elle est démarrée.

6.3 Suivre et annuler

Commande Effet
docker service ps app_api Montre les anciennes tâches (arrêtées) et les nouvelles
docker service inspect --pretty app_api Affiche l'état de la mise à jour (UpdateStatus)
docker service rollback app_api Revient à la configuration précédente du service

Avec failure_action: rollback, Swarm revient automatiquement à la version précédente si la mise à jour échoue. Les paramètres du retour arrière se règlent avec rollback_config.

7. Tolérance aux pannes et exploitation

7.1 Ce que Swarm répare seul

Panne Réaction de Swarm
Un conteneur s'arrête La tâche est recréée, selon la restart_policy
Un conteneur est unhealthy Swarm le remplace par une nouvelle tâche (contrairement à Docker seul, chapitre 8)
Un nœud tombe Ses tâches sont recréées sur les autres nœuds
Un manager tombe Un autre manager devient leader, si le quorum est conservé (chapitre 11)

7.2 Ce que Swarm ne répare pas

  • les données locales d'un nœud perdu (section 5.1) ;
  • la perte du quorum des managers : il faut rétablir assez de managers ;
  • une application qui échoue systématiquement : Swarm la recrée en boucle, selon sa politique de redémarrage ;
  • une image introuvable ou incorrecte.

7.3 Politique de redémarrage

deploy:
  restart_policy:
    condition: on-failure
    delay: 5s
    max_attempts: 3
Condition Effet
none Pas de redémarrage
on-failure Redémarre si la tâche s'arrête avec une erreur
any Redémarre toujours (valeur par défaut)

8. Diagnostiquer une stack

Reprenez la démarche du chapitre 8 en y ajoutant les outils de Swarm :

Question Outil
La stack est-elle déployée comme prévu ? docker stack services app
Où sont les tâches et pourquoi certaines échouent-elles ? docker stack ps app --no-trunc
Que dit un service ? docker service logs app_api
Le nom d'un service est-il résolu ? Depuis une tâche : ping ou nslookup sur le nom court
Les secrets et configs sont-ils présents ? docker secret ls, docker config ls, et le fichier monté dans la tâche
La mise à jour est-elle bloquée ? docker service inspect --pretty app_api (UpdateStatus)
Un nœud est-il en cause ? docker node ls, docker node inspect --pretty

9. Swarm et Kubernetes

Docker Swarm n'est pas le seul orchestrateur : Kubernetes est aujourd'hui l'orchestrateur le plus répandu. Ce que vous avez appris ici se transpose en grande partie : les concepts sont proches, la mise en œuvre diffère.

Concept Docker Swarm Kubernetes (équivalent approximatif)
Unité d'exécution Tâche (un conteneur) Pod (un ou plusieurs conteneurs)
Application répliquée Service répliqué Deployment
Accès réseau à un service VIP, routing mesh Service
Un pod ou une tâche par nœud Service global DaemonSet
Description de l'application Fichier de stack Manifestes (fichiers YAML)
Données non sensibles / sensibles Config / Secret ConfigMap / Secret
Mise à jour progressive update_config, rollback Stratégie du Deployment, rollout undo
Placement Contraintes, étiquettes Sélecteurs, affinités, taints
Docker Swarm Kubernetes
Installation Intégré à Docker : docker swarm init Composant à installer et à configurer
Prise en main Rapide, reprend Compose Plus longue, plus de concepts
Fonctionnalités Essentielles Très riches, extensibles
Écosystème Plus restreint Très vaste
Cas d'usage Petits et moyens déploiements, équipes réduites Grandes infrastructures, besoins avancés

Choisir un outil

Le choix dépend de la taille de l'infrastructure, des compétences de l'équipe et des besoins. Swarm permet de comprendre rapidement les principes d'orchestration ; vous les retrouverez dans le cours Kubernetes de ce Master.

À retenir

  • Une stack déploie une application complète à partir d'un fichier Compose avec une section deploy ; docker stack deploy crée et met à jour.
  • Un réseau overlay relie les services sur plusieurs nœuds ; les services se joignent par leur nom.
  • Une stack utilise des images publiées dans un registre ; build et depends_on sont ignorés.
  • Configs et secrets sont des objets du cluster, immuables ; les secrets sont chiffrés et montés en mémoire sous /run/secrets/.
  • Les contraintes de placement (node.role, node.hostname, étiquettes) contrôlent où tournent les tâches.
  • Un volume est local à un nœud : un service avec des données doit être fixé à un nœud ou utiliser un stockage partagé.
  • Les mises à jour sont progressives (parallelism, delay, order) ; failure_action: rollback revient en arrière automatiquement.
  • Swarm recrée les tâches en échec ou unhealthy et réattribue celles d'un nœud perdu.

Pour vérifier votre compréhension

Pourquoi docker stack deploy ignore-t-il la clé build ?

Les tâches peuvent être placées sur n'importe quel nœud, qui télécharge lui-même l'image. Une stack doit donc utiliser des images déjà construites et publiées dans un registre accessible à tous les nœuds.

Un service db a un volume nommé. Le nœud qui l'héberge tombe. Que se passe-t-il ?

Swarm recrée la tâche sur un autre nœud, où le volume nommé est vide : les données restent sur le nœud en panne. Il faut fixer le service à un nœud, utiliser un stockage partagé ou une base hors du cluster.

Quel avantage a order: start-first pour une mise à jour ?

La nouvelle tâche est démarrée avant l'arrêt de l'ancienne : la capacité du service ne baisse pas pendant la mise à jour. Il faut que l'application supporte la coexistence de deux versions.

Pourquoi crée-t-on un nouveau secret plutôt que de modifier un secret existant ?

Les secrets et configs sont immuables. Pour changer une valeur, on crée un nouvel objet, on met le service à jour pour l'utiliser, puis on supprime l'ancien.

Quelle différence principale entre une tâche Swarm et un pod Kubernetes ?

Une tâche correspond à un seul conteneur, alors qu'un pod peut regrouper plusieurs conteneurs qui partagent le réseau et le stockage. Les deux sont l'unité que l'orchestrateur place sur un nœud.

Ressources du chapitre