Docker Swarm exercises and projects
Chapter objectives
- Consolidate the knowledge acquired
- Practice with real-world scenarios
- Complete full projects
- Prepare for production
1 - Basic exercises
Exercise 1: Cluster initialization
Objective: Create a basic Swarm cluster
# 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:
- What does the join token contain?
- Why use
--advertise-addr?
Exercise 2: Scaling and rolling updates
Objective: Master scaling and updates
# 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
Exercise 3: Overlay networks
Objective: Configure inter-service communication
# 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 - Intermediate exercises
Exercise 4: Secrets and configurations
Objective: Manage sensitive data
# 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
Exercise 5: Placement constraints
Objective: Control the placement of 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
Exercise 6: Complete stack
Objective: Deploy a multi-service application
Create the stack.yml file:
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 - Complete projects
Project 1: High availability web application
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
Deployment:
# 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
Project 2: Monitoring stack
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 - Review quiz
Questions
-
What is the minimum number of managers for tolerance to 1 failure?
-
Which command puts a node in maintenance?
-
How do you create an encrypted overlay network?
-
What is the difference between VIP mode and DNSRR?
-
How do you access secrets in a container?
-
Which option guarantees a rolling update without downtime?
-
How do you force the redeployment of a service's tasks?
-
What is the quorum for a cluster of 5 managers?
Answers
See the answers
-
3 managers (quorum = 2, tolerates 1 failure)
-
docker node update --availability drain <node> -
docker network create --driver overlay --opt encrypted <name> -
VIP: a single virtual IP with transparent LB. DNSRR: DNS returns all IPs, client-side LB
-
Secrets are available in
/run/secrets/<name> -
--update-order start-first(starts the new one before stopping the old one) -
docker service update --force <service> -
Quorum = 3 (5/2 + 1 = 3)
5 - Advanced challenges
Challenge 1: Blue-Green Deployment
Implement a blue-green deployment:
- "blue" service active on port 80
- Deploy "green" on port 8080
- Test green
- Switch the traffic
- Remove blue
Challenge 2: Auto-scaling
Create a script that:
- Monitors the CPU usage of services
- Automatically scales between 2 and 10 replicas
- Logs the scaling actions
Challenge 3: Disaster Recovery
Set up:
- Automatic daily backup
- Tested restore script
- Documented recovery procedure
Course summary
You have learned:
- The architecture and concepts of Docker Swarm
- Creating and managing clusters
- Services, tasks and stacks
- Overlay networking and routing mesh
- Managing secrets and configurations
- Scaling and load balancing
- High availability
- Production best practices
- Practice with real environments
- Explore Kubernetes for advanced needs
- Integrate Swarm into your CI/CD pipelines
- Certify your Docker skills