Exercices et Projets Docker Swarm
Objectifs du chapitre
- Consolider les connaissances acquises
- Pratiquer avec des scénarios réels
- Réaliser des projets complets
- Se préparer à la production
1 - Exercices de base
Exercice 1 : Initialisation du cluster
Objectif : Créer un cluster Swarm basique
# 1. Initialiser le Swarm
docker swarm init --advertise-addr <votre-ip>
# 2. Vérifier l'état
docker node ls
docker info | grep -i swarm
# 3. Créer votre premier service
docker service create --name hello --replicas 3 -p 80:80 nginx:alpine
# 4. Vérifier le service
docker service ls
docker service ps hello
# 5. Tester l'accès
curl http://localhost
# 6. Nettoyer
docker service rm hello
Questions :
- Que contient le token de join ?
- Pourquoi utiliser
--advertise-addr?
Exercice 2 : Scaling et rolling updates
Objectif : Maîtriser le scaling et les mises à jour
# 1. Créer un service
docker service create --name web \
--replicas 3 \
--update-parallelism 1 \
--update-delay 10s \
nginx:1.24-alpine
# 2. Observer les tâches
watch docker service ps web
# 3. Scaler à 10 réplicas
docker service scale web=10
# 4. Mettre à jour l'image
docker service update --image nginx:1.25-alpine web
# 5. Observer le rolling update
docker service ps web
# 6. Faire un rollback
docker service rollback web
Exercice 3 : Réseaux overlay
Objectif : Configurer la communication inter-services
# 1. Créer un réseau overlay
docker network create --driver overlay app-network
# 2. Créer un service backend
docker service create --name api \
--network app-network \
--replicas 2 \
nginx:alpine
# 3. Créer un service frontend
docker service create --name web \
--network app-network \
--replicas 2 \
-p 80:80 \
nginx:alpine
# 4. Tester la connectivité
docker exec -it $(docker ps -q -f name=web) ping api
# 5. Vérifier le DNS interne
docker exec -it $(docker ps -q -f name=web) nslookup api
2 - Exercices intermédiaires
Exercice 4 : Secrets et configurations
Objectif : Gérer les données sensibles
# 1. Créer un secret
echo "supersecret123" | docker secret create db_password -
# 2. Créer une configuration
cat << EOF > nginx.conf
server {
listen 80;
location / {
return 200 'Hello from Swarm!';
}
}
EOF
docker config create nginx_conf nginx.conf
# 3. Créer un service utilisant le secret et la config
docker service create --name secure-app \
--secret db_password \
--config source=nginx_conf,target=/etc/nginx/conf.d/default.conf \
nginx:alpine
# 4. Vérifier l'accès au secret (dans le conteneur)
docker exec -it $(docker ps -q -f name=secure-app) cat /run/secrets/db_password
Exercice 5 : Contraintes de placement
Objectif : Contrôler le placement des services
# 1. Ajouter des labels aux nœuds
docker node update --label-add env=production $(docker node ls -q | head -1)
docker node update --label-add type=web $(docker node ls -q | head -1)
# 2. Créer un service avec contraintes
docker service create --name prod-only \
--constraint 'node.labels.env==production' \
--replicas 3 \
nginx:alpine
# 3. Vérifier le placement
docker service ps prod-only
# 4. Tester une contrainte impossible
docker service create --name impossible \
--constraint 'node.labels.env==staging' \
--replicas 2 \
nginx:alpine
# Observer que le service ne peut pas démarrer
# 5. Utiliser des préférences de spread
docker service create --name spread-test \
--replicas 6 \
--placement-pref 'spread=node.labels.type' \
nginx:alpine
Exercice 6 : Stack complète
Objectif : Déployer une application multi-services
Créez le fichier stack.yml :
version: "3.9"
services:
web:
image: nginx:alpine
ports:
- "80:80"
networks:
- frontend
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
api:
image: httpd:alpine
networks:
- frontend
- backend
deploy:
replicas: 2
db:
image: postgres:15-alpine
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_pass
secrets:
- db_pass
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
db-data:
secrets:
db_pass:
file: ./db_password.txt
# Créer le fichier de secret
echo "mydbpassword" > db_password.txt
# Déployer la stack
docker stack deploy -c stack.yml myapp
# Vérifier
docker stack services myapp
docker stack ps myapp
# Supprimer
docker stack rm myapp
3 - Projets complets
Projet 1 : Application web haute disponibilité
Architecture :
Internet
│
▼
┌───────────────┐
│ Traefik │
│ (Reverse │
│ Proxy) │
└───────┬───────┘
│
┌────────────┼────────────┐
│ │ │
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ Web 1 │ │ Web 2 │ │ Web 3 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
└────────────┼────────────┘
│
▼
┌───────────────┐
│ PostgreSQL │
│ (Primary) │
└───────────────┘
docker-compose.yml :
version: "3.9"
services:
traefik:
image: traefik:v2.10
command:
- "--api.dashboard=true"
- "--providers.docker=true"
- "--providers.docker.swarmMode=true"
- "--providers.docker.exposedbydefault=false"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
ports:
- "80:80"
- "443:443"
- "8080:8080"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
networks:
- traefik-public
deploy:
mode: global
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.http.routers.dashboard.rule=Host(`traefik.localhost`)"
- "traefik.http.routers.dashboard.service=api@internal"
web:
image: nginx:alpine
networks:
- traefik-public
- backend
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 30s
failure_action: rollback
labels:
- "traefik.enable=true"
- "traefik.http.routers.web.rule=Host(`app.localhost`)"
- "traefik.http.services.web.loadbalancer.server.port=80"
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
api:
image: httpd:alpine
networks:
- traefik-public
- backend
deploy:
replicas: 2
labels:
- "traefik.enable=true"
- "traefik.http.routers.api.rule=Host(`api.localhost`)"
- "traefik.http.services.api.loadbalancer.server.port=80"
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app"]
interval: 30s
timeout: 10s
retries: 5
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- backend
deploy:
replicas: 1
networks:
traefik-public:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
db-data:
redis-data:
secrets:
db_password:
external: true
Déploiement :
# Préparer
docker node update --label-add db=true $(docker node ls -q | head -1)
echo "secretpassword" | docker secret create db_password -
# Déployer
docker stack deploy -c docker-compose.yml webapp
# Tester
curl -H "Host: app.localhost" http://localhost
curl -H "Host: api.localhost" http://localhost
# Monitoring
watch docker stack services webapp
Projet 2 : Stack de monitoring
docker-compose.monitoring.yml :
version: "3.9"
services:
prometheus:
image: prom/prometheus:v2.47.0
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.enable-lifecycle'
volumes:
- prometheus-data:/prometheus
configs:
- source: prometheus_config
target: /etc/prometheus/prometheus.yml
networks:
- monitoring
deploy:
replicas: 1
placement:
constraints:
- node.role == manager
grafana:
image: grafana/grafana:10.1.0
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
- GF_USERS_ALLOW_SIGN_UP=false
volumes:
- grafana-data:/var/lib/grafana
networks:
- monitoring
- traefik-public
deploy:
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.http.routers.grafana.rule=Host(`grafana.localhost`)"
- "traefik.http.services.grafana.loadbalancer.server.port=3000"
cadvisor:
image: gcr.io/cadvisor/cadvisor:latest
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker:/var/lib/docker:ro
networks:
- monitoring
deploy:
mode: global
node-exporter:
image: prom/node-exporter:v1.6.1
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/)'
networks:
- monitoring
deploy:
mode: global
alertmanager:
image: prom/alertmanager:v0.26.0
volumes:
- alertmanager-data:/alertmanager
configs:
- source: alertmanager_config
target: /etc/alertmanager/alertmanager.yml
networks:
- monitoring
deploy:
replicas: 1
networks:
monitoring:
driver: overlay
traefik-public:
external: true
volumes:
prometheus-data:
grafana-data:
alertmanager-data:
configs:
prometheus_config:
file: ./prometheus.yml
alertmanager_config:
file: ./alertmanager.yml
4 - Quiz de révision
Questions
-
Quel est le nombre minimum de managers pour une tolérance à 1 panne ?
-
Quelle commande permet de mettre un nœud en maintenance ?
-
Comment créer un réseau overlay chiffré ?
-
Quelle est la différence entre mode VIP et DNSRR ?
-
Comment accéder aux secrets dans un conteneur ?
-
Quelle option garantit un rolling update sans downtime ?
-
Comment forcer le redéploiement des tâches d'un service ?
-
Quel est le quorum pour un cluster de 5 managers ?
Réponses
Voir les réponses
-
3 managers (quorum = 2, tolère 1 panne)
-
docker node update --availability drain <node> -
docker network create --driver overlay --opt encrypted <name> -
VIP : une seule IP virtuelle avec LB transparent. DNSRR : DNS retourne toutes les IPs, LB côté client
-
Les secrets sont disponibles dans
/run/secrets/<name> -
--update-order start-first(démarre le nouveau avant d'arrêter l'ancien) -
docker service update --force <service> -
Quorum = 3 (5/2 + 1 = 3)
5 - Défis avancés
Défi 1 : Blue-Green Deployment
Implémentez un déploiement blue-green :
- Service "blue" actif sur le port 80
- Déployez "green" sur le port 8080
- Testez green
- Basculez le trafic
- Supprimez blue
Défi 2 : Auto-scaling
Créez un script qui :
- Surveille l'utilisation CPU des services
- Scale automatiquement entre 2 et 10 réplicas
- Log les actions de scaling
Défi 3 : Disaster Recovery
Mettez en place :
- Backup automatique quotidien
- Script de restauration testé
- Procédure documentée de recovery
Résumé du cours
Vous avez appris :
- L'architecture et les concepts Docker Swarm
- La création et gestion de clusters
- Les services, tasks et stacks
- Le networking overlay et routing mesh
- La gestion des secrets et configurations
- Le scaling et load balancing
- La haute disponibilité
- Les bonnes pratiques de production
- Pratiquez avec des environnements réels
- Explorez Kubernetes pour des besoins avancés
- Intégrez Swarm dans vos pipelines CI/CD
- Certifiez vos compétences Docker