🔁 DevOps

devops-docker-swarm-guide

Orchestration avec Docker Swarm incluant services, stacks, overlay networks, secrets, rolling updates et haute disponibilité.

⚡ Installation & lancement en 1 commande

Copiez-collez dans votre terminal : le skill s'installe dans ~/.claude/skills et Claude Code se lance directement dessus.

macOS / Linux
curl -fsSL https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.sh | sh -s -- devops-docker-swarm-guide --launch
Windows (PowerShell)
iex "& { $(iwr -useb https://raw.githubusercontent.com/khalilbenaz/claude-skills-collection/main/install.ps1) } devops-docker-swarm-guide -Launch"

🚀 Déjà installé ?

claude "/devops-docker-swarm-guide"

Ou tapez /devops-docker-swarm-guide dans une session Claude Code, ou décrivez simplement votre besoin — le skill se déclenche automatiquement via le skill-router.

🔑 Déclencheurs automatiques

Le skill s'active automatiquement quand votre demande contient :

Docker Swarmswarm modedocker servicedocker stack

📦 Installation manuelle

git clone https://github.com/khalilbenaz/claude-skills-collection.git cp -r claude-skills-collection/skills/devops-docker-swarm-guide ~/.claude/skills/

Payload du plugin : skills/devops-docker-swarm-guide · source éditable : devops-skills/docker-swarm-guide

📖 Manuel

Docker Swarm Guide

Critères de choix : Swarm vs Kubernetes

CritèreSwarmKubernetes
Équipe < 5 devops❌ complexité op
Infra on-premise simplepossible mais lourd
Multitenancy avancé
RBAC fin, CRDs, Operators
Stack existante Docker Compose✅ migration facileconversion nécessaire

Choisis Swarm si tu as déjà des Compose files, une petite équipe, et pas besoin de scaling horizontal à 100+ nœuds.


Workflow en étapes

1. Initialiser le cluster

# Sur le premier manager (remplace l'IP par l'IP privée réseau inter-nœuds)
docker swarm init --advertise-addr 192.168.1.10

# Récupérer les tokens
docker swarm join-token manager   # pour ajouter un manager
docker swarm join-token worker    # pour ajouter un worker

# Rejoindre depuis un autre nœud
docker swarm join --token SWMTKN-1-xxx 192.168.1.10:2377

# Vérifier l'état du cluster
docker node ls

Règle de quorum Raft : toujours un nombre impair de managers.

# Promouvoir un worker en manager
docker node promote <node-id>

# Vérifier la santé du Raft
docker node inspect self --format '{{ .ManagerStatus.Reachability }}'

2. Configurer les overlay networks

# Réseau chiffré pour données sensibles
docker network create \
  --driver overlay \
  --opt encrypted \
  --subnet 10.0.1.0/24 \
  backend-net

# Réseau frontend non chiffré (moins de CPU)
docker network create --driver overlay frontend-net

Pattern d'isolation recommandé :

# Réseau attachable pour debug/tests ad hoc
docker network create --driver overlay --attachable debug-net

3. Déployer un service

# Service minimal avec réplicas
docker service create \
  --name api \
  --replicas 3 \
  --network backend-net \
  --publish published=8080,target=3000 \
  --limit-cpu 0.5 \
  --limit-memory 256M \
  --reserve-cpu 0.25 \
  --reserve-memory 128M \
  --health-cmd "curl -f http://localhost:3000/health || exit 1" \
  --health-interval 10s \
  --health-retries 3 \
  myrepo/api:1.2.0

# Inspecter les tasks et leur état
docker service ps api --no-trunc

Contraintes de placement :

# Forcer sur nœuds labellisés SSD
docker node update --label-add disk=ssd worker-1

docker service create \
  --constraint 'node.labels.disk == ssd' \
  --name db \
  postgres:16

4. Stacks avec docker-compose (méthode recommandée)

# docker-compose.prod.yml
version: "3.9"

services:
  api:
    image: myrepo/api:${API_VERSION:-latest}
    networks:
      - frontend-net
      - backend-net
    secrets:
      - db_password
    environment:
      DB_HOST: db
    deploy:
      replicas: 3
      update_config:
        parallelism: 1
        delay: 15s
        failure_action: rollback
        monitor: 30s
        order: start-first       # zero-downtime : nouveau container avant l'arrêt
      rollback_config:
        parallelism: 1
        delay: 10s
        failure_action: pause
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
      resources:
        limits:
          cpus: "0.5"
          memory: 256M
        reservations:
          cpus: "0.25"
          memory: 128M
      placement:
        constraints:
          - node.role == worker
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
      interval: 10s
      timeout: 5s
      retries: 3
      start_period: 20s

  db:
    image: postgres:16
    networks:
      - backend-net
    secrets:
      - db_password
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    volumes:
      - db-data:/var/lib/postgresql/data
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.disk == ssd

networks:
  frontend-net:
    driver: overlay
  backend-net:
    driver: overlay
    driver_opts:
      encrypted: "true"

volumes:
  db-data:

secrets:
  db_password:
    external: true
# Déployer / mettre à jour la stack
docker stack deploy -c docker-compose.prod.yml myapp

# Lister les services de la stack
docker stack services myapp

# Retirer la stack (ne supprime pas les volumes)
docker stack rm myapp

5. Gérer secrets et configs

# Créer un secret depuis stdin (jamais depuis un fichier en clair en prod)
echo "S3cr3tP@ss" | docker secret create db_password -

# Depuis un fichier
docker secret create tls_cert ./cert.pem

# Lister / inspecter (le contenu n'est jamais affiché)
docker secret ls
docker secret inspect db_password

# Config (non sensible — fichiers de conf, templates)
docker config create nginx_conf ./nginx.conf

# Usage dans un service
docker service update \
  --config-add source=nginx_conf,target=/etc/nginx/nginx.conf \
  nginx

Les secrets sont montés en RAM (tmpfs) dans /run/secrets/<nom>. Ils ne touchent jamais le disque du worker.


6. Rolling updates et rollbacks

# Mise à jour de l'image (zero-downtime avec order: start-first)
docker service update \
  --image myrepo/api:1.3.0 \
  --update-parallelism 1 \
  --update-delay 15s \
  --update-failure-action rollback \
  api

# Suivre la progression
docker service ps api --filter desired-state=running

# Rollback manuel immédiat
docker service rollback api

# Forcer un redémarrage sans changer l'image (ex. secrets modifiés)
docker service update --force api

7. Services globaux et monitoring

# Déployer un agent Prometheus Node Exporter sur CHAQUE nœud
docker service create \
  --name node-exporter \
  --mode global \
  --network monitoring-net \
  --mount type=bind,src=/proc,dst=/host/proc,ro=true \
  --mount type=bind,src=/sys,dst=/host/sys,ro=true \
  prom/node-exporter:latest

Garde-fous et anti-patterns

❌ Ne jamais faire

# DANGER : expose les secrets dans docker inspect / logs
docker service create -e DB_PASSWORD=secret123 myapp

# DANGER : manager utilisé comme worker en prod
# (le manager gère le Raft — surcharge CPU = instabilité quorum)
docker node update --availability drain manager-1  # ← correct pour drainer

# DANGER : volume local partagé entre réplicas sans NFS/Ceph
# Chaque réplica sur son nœud a sa propre copie locale → incohérence

⚠️ Pièges courants

PiègeSymptômeSolution
update_config.order: stop-first (défaut)Downtime pendant updatePasser à start-first
Pas de healthcheckTasks "Running" mais app downToujours définir un healthcheck
Pas de resource limitsUn service OOM tue le nœudToujours limiter CPU + RAM
Quorum perdu (2 managers sur 3 HS)Cluster en read-onlyRestaurer via docker swarm init --force-new-cluster
Image latest en prodRollback impossibleToujours tagger les versions
Drain d'un nœud sans vérifier les réplicasRéplicas reschedulés sur nœuds surchargésSurveiller docker service ps après drain

Commandes de diagnostic

# État global du cluster
docker node ls
docker service ls

# Tasks en échec
docker service ps <service> --filter desired-state=shutdown

# Logs d'un service (toutes les tasks)
docker service logs --follow --tail 100 api

# Inspecter un nœud (labels, ressources)
docker node inspect <node-id> --pretty

# Stats CPU/mémoire des containers sur le nœud local
docker stats --no-stream

Bonnes pratiques 2026