Stacks et déploiement
Objectifs du chapitre
- Comprendre les stacks Docker
- Écrire des fichiers de stack (docker-compose)
- Déployer et gérer des stacks
- Utiliser les options de déploiement
1 - Qu'est-ce qu'une Stack ?
Définition
Une stack est un groupe de services liés, définis dans un fichier YAML et déployés ensemble.
┌─────────────────────────────────────────────────────────────┐
│ Stack "myapp" │
├─────────────────────────── ──────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Service: web (3 replicas) │ │
│ │ Service: api (2 replicas) │ │
│ │ Service: db (1 replica) │ │
│ │ Service: redis (1 replica) │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Network: frontend │ │
│ │ Network: backend │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Volume: db-data │ │
│ │ Config: nginx-config │ │
│ │ Secret: db-password │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────── ──┘
Stack vs Docker Compose
| Aspect | Docker Compose | Docker Stack |
|---|---|---|
| Mode | Standalone | Swarm |
| Commande | docker compose up | docker stack deploy |
| Build | Oui | Non (images pré-construites) |
depends_on | Oui | Non |
deploy | Ignoré | Utilisé |
2 - Fichier de Stack
Structure de base
version: "3.9"
services:
web:
image: nginx:alpine
ports:
- "80:80"
deploy:
replicas: 3
api:
image: myapi:latest
deploy:
replicas: 2
networks:
default:
driver: overlay
volumes:
data:
Section deploy
services:
web:
image: nginx
deploy:
# Nombre de réplicas
replicas: 3
# Mode de déploiement
mode: replicated # ou global
# Placement
placement:
constraints:
- node.role == worker
- node.labels.zone == eu-west
preferences:
- spread: node.labels.zone
# Ressources
resources:
limits:
cpus: '0.5'
memory: 256M
reservations:
cpus: '0.25'
memory: 128M
# Stratégie de mise à jour
update_config:
parallelism: 2
delay: 10s
failure_action: rollback
order: start-first
# Stratégie de rollback
rollback_config:
parallelism: 1
delay: 5s
# Politique de redémarrage
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
# Labels
labels:
com.example.description: "Web frontend"
3 - Déployer une Stack
Commande de base
# Déployer une stack
docker stack deploy -c docker-compose.yml myapp
# Avec plusieurs fichiers
docker stack deploy \
-c docker-compose.yml \
-c docker-compose.prod.yml \
myapp
Vérifier le déploiement
# Lister les stacks
docker stack ls
# Services d'une stack
docker stack services myapp
# Tâches d'une stack
docker stack ps myapp
# Tâches avec filtres
docker stack ps myapp --filter "desired-state=running"
Mettre à jour une stack
# Re-déployer avec les changements
docker stack deploy -c docker-compose.yml myapp
# Swarm compare l'état désiré et applique les différences
Supprimer une stack
# Supprimer
docker stack rm myapp
# Attention : supprime tous les services, réseaux (pas les volumes)
4 - Exemple complet : Application web
docker-compose.yml
version: "3.9"
services:
# Reverse proxy / Load balancer
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
configs:
- source: nginx_config
target: /etc/nginx/conf.d/default.conf
networks:
- frontend
deploy:
replicas: 2
placement:
constraints:
- node.role == manager
update_config:
parallelism: 1
delay: 10s
# Application API
api:
image: myregistry/api:${VERSION:-latest}
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://postgres:${DB_PASSWORD}@db:5432/app
- REDIS_URL=redis://redis:6379
networks:
- frontend
- backend
secrets:
- db_password
- jwt_secret
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
update_config:
parallelism: 1
delay: 30s
failure_action: rollback
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
# Base de données
db:
image: postgres:15-alpine
environment:
- POSTGRES_DB=app
- POSTGRES_PASSWORD_FILE=/run/secrets/db_password
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
secrets:
- db_password
deploy:
replicas: 1
placement:
constraints:
- node.labels.db == true
resources:
limits:
cpus: '2'
memory: 2G
# Cache Redis
redis:
image: redis:7-alpine
command: redis-server --appendonly yes
volumes:
- redis-data:/data
networks:
- backend
deploy:
replicas: 1
# Worker pour les jobs asynchrones
worker:
image: myregistry/worker:${VERSION:-latest}
environment:
- DATABASE_URL=postgres://postgres:${DB_PASSWORD}@db:5432/app
- REDIS_URL=redis://redis:6379
networks:
- backend
secrets:
- db_password
deploy:
replicas: 2
resources:
limits:
cpus: '0.5'
memory: 256M
networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true
volumes:
db-data:
redis-data:
configs:
nginx_config:
file: ./nginx-default.conf
secrets:
db_password:
external: true
jwt_secret:
external: true
Déploiement
# Créer les secrets d'abord
echo "supersecretpassword" | docker secret create db_password -
echo "jwtsecretkey" | docker secret create jwt_secret -
# Déployer
VERSION=1.0.0 docker stack deploy -c docker-compose.yml myapp
# Vérifier
docker stack services myapp
5 - Variables et fichiers d'environnement
Utiliser des variables
services:
api:
image: myapi:${VERSION:-latest}
environment:
- LOG_LEVEL=${LOG_LEVEL:-info}
# Avec variables d'environnement
VERSION=2.0.0 LOG_LEVEL=debug docker stack deploy -c stack.yml myapp
# Avec fichier .env
export $(cat .env | xargs) && docker stack deploy -c stack.yml myapp
Fichier .env
# .env
VERSION=1.2.3
LOG_LEVEL=info
DB_PASSWORD=secret
DOMAIN=example.com
6 - Fichiers multiples
Fichier de base + overrides
# docker-compose.yml (base)
version: "3.9"
services:
api:
image: myapi:latest
networks:
- backend
# docker-compose.prod.yml (override production)
version: "3.9"
services:
api:
deploy:
replicas: 5
resources:
limits:
memory: 1G
# Combiner les fichiers
docker stack deploy \
-c docker-compose.yml \
-c docker-compose.prod.yml \
myapp
Organisation recommandée
project/
├── docker-compose.yml # Base
├── docker-compose.prod.yml # Production overrides
├── docker-compose.dev.yml # Development overrides
├── configs/
│ └── nginx.conf
├── secrets/
│ └── .gitkeep
└── scripts/
├── deploy-prod.sh
└── deploy-staging.sh
7 - Healthchecks et dépendances
Healthcheck dans la stack
services:
api:
image: myapi
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
deploy:
replicas: 3
Gérer les dépendances (sans depends_on)
services:
api:
image: myapi
deploy:
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 10
# L'API redémarre jusqu'à ce que db soit prête
db:
image: postgres:15
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
8 - Bonnes pratiques
Images
services:
api:
# ✅ Toujours utiliser des tags versionnés
image: myregistry/api:1.2.3
# ❌ Éviter latest en production
# image: myregistry/api:latest
Ressources
services:
api:
deploy:
resources:
# ✅ Toujours définir des limites
limits:
cpus: '1'
memory: 512M
# ✅ Définir des réservations pour le scheduling
reservations:
cpus: '0.25'
memory: 256M
Réseaux
networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true # ✅ Isoler le backend
# ❌ Éviter un seul réseau pour tout
Mises à jour
services:
api:
deploy:
update_config:
parallelism: 1 # Un à la fois
delay: 30s # Attendre entre chaque
failure_action: rollback # Rollback si échec
order: start-first # Nouveau avant de tuer l'ancien
Résumé des commandes
| Commande | Description |
|---|---|
docker stack deploy -c file.yml name | Déployer une stack |
docker stack ls | Lister les stacks |
docker stack services name | Services d'une stack |
docker stack ps name | Tâches d'une stack |
docker stack rm name | Supprimer une stack |
Points clés
- Les stacks utilisent la section
deploydu docker-compose depends_onn'est pas supporté, utilisez healthchecks + restart- Utilisez des tags versionnés, pas
latest - Définissez toujours des limites de ressources
Exercices pratiques
- Créez une stack avec nginx + api + redis
- Configurez le rolling update pour zéro downtime
- Ajoutez des healthchecks à tous les services
- Testez la mise à jour d'un service dans la stack