Aller au contenu principal

Bonnes pratiques Docker Swarm


Objectifs du chapitre

  • Appliquer les bonnes pratiques de production
  • Sécuriser votre cluster Swarm
  • Optimiser les performances
  • Standardiser les déploiements

1 - Architecture du cluster

Dimensionnement

Production Standard:
┌─────────────────────────────────────────────────────────────┐
│ │
│ Managers (3 ou 5) Workers (N) │
│ ┌───────────────┐ ┌───────────────┐ │
│ │ RAM: 4-8 Go │ │ RAM: 2-16 Go │ │
│ │ CPU: 2-4 cores│ │ CPU: 2-8 cores│ │
│ │ SSD: 50 Go │ │ SSD: 50+ Go │ │
│ └───────────────┘ └───────────────┘ │
│ │
│ Managers: gestion uniquement │
│ Workers: exécution des charges de travail │
│ │
└─────────────────────────────────────────────────────────────┘

Recommandations

ComposantMinimumRecommandé
Managers35
Workers2Selon charge
RAM Manager4 Go8 Go
RAM Worker2 Go4-16 Go
StockageSSD 50 GoSSD 100+ Go

Séparation des rôles

# Ne pas exécuter de charges de travail sur les managers
docker node update --availability drain manager1
docker node update --availability drain manager2
docker node update --availability drain manager3

# Ou utiliser des contraintes
docker service create --name app \
--constraint 'node.role==worker' \
myapp

2 - Sécurité

Chiffrement

# Activer l'autolock (chiffrement au repos)
docker swarm update --autolock=true

# Sauvegarder la clé de déverrouillage !
docker swarm unlock-key

# Rotation régulière de la clé
docker swarm unlock-key --rotate

Rotation des certificats

# Réduire la durée des certificats (par défaut 90 jours)
docker swarm update --cert-expiry 48h

# Forcer la rotation
docker swarm ca --rotate

Réseaux sécurisés

# Chiffrer le trafic overlay
docker network create --driver overlay --opt encrypted secure-net

# Réseau interne (pas d'accès externe)
docker network create --driver overlay --internal backend-net

Secrets et configs

# ✅ Utiliser des secrets pour les données sensibles
secrets:
db_password:
external: true

# ❌ Ne jamais faire
environment:
- DB_PASSWORD=plaintext

Principe du moindre privilège

services:
app:
# Utilisateur non-root
user: "1000:1000"

# Lecture seule si possible
read_only: true

# Limiter les capabilities
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE

# Pas de privilege escalation
security_opt:
- no-new-privileges:true

3 - Images et registres

Versions d'images

# ✅ Toujours utiliser des tags versionnés
services:
web:
image: myregistry/web:1.2.3

# ❌ Éviter
services:
web:
image: myregistry/web:latest

Registre privé

# Déployer un registre dans le cluster
docker service create --name registry \
--publish 5000:5000 \
--mount type=volume,source=registry-data,target=/var/lib/registry \
--constraint 'node.role==manager' \
registry:2

# Utiliser les credentials
docker service create --name app \
--with-registry-auth \
myregistry/app:1.0

Signer les images

# Activer le content trust
export DOCKER_CONTENT_TRUST=1

# Signer et pousser
docker push myregistry/app:1.0

4 - Déploiements

Rolling updates

services:
app:
deploy:
replicas: 5
update_config:
parallelism: 1 # Un à la fois
delay: 30s # Délai entre chaque
failure_action: rollback
monitor: 60s # Surveillance après update
order: start-first # Nouveau avant l'ancien
rollback_config:
parallelism: 1
delay: 10s

Healthchecks obligatoires

services:
api:
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s

Zero-downtime deployment

services:
web:
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 30s
order: start-first # Démarre le nouveau AVANT d'arrêter l'ancien
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 30s

5 - Gestion des ressources

Limites obligatoires

services:
app:
deploy:
resources:
limits:
cpus: '1'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M

Éviter le sur-provisionnement

# Calculer la capacité du cluster
Total Workers: 3 nœuds × 8 Go RAM = 24 Go

# Réserver pour le système
Disponible: 24 Go - (3 × 1 Go système) = 21 Go

# Planifier les services
Service A: 5 replicas × 512 Mo = 2.5 Go
Service B: 3 replicas × 1 Go = 3 Go
...

6 - Networking

Isolation réseau

services:
nginx:
networks:
- frontend

api:
networks:
- frontend
- backend

db:
networks:
- backend # Pas d'accès depuis frontend

networks:
frontend:
driver: overlay
backend:
driver: overlay
internal: true

DNS et service discovery

# Utiliser des noms de service, pas des IPs
services:
api:
environment:
- DATABASE_HOST=db
- REDIS_HOST=redis
- CACHE_HOST=memcached

Éviter le mode host

# ✅ Mode ingress (load balancing)
ports:
- "80:80"

# ⚠️ Mode host (cas spécifiques uniquement)
ports:
- target: 80
published: 80
mode: host

7 - Logging et monitoring

Centraliser les logs

services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"

# Ou avec un driver centralisé
app-centralized:
logging:
driver: "fluentd"
options:
fluentd-address: "localhost:24224"
tag: "docker.{{.Name}}"

Stack de monitoring

version: "3.9"

services:
prometheus:
image: prom/prometheus:v2.47.0
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus-data:/prometheus
deploy:
placement:
constraints:
- node.role == manager

grafana:
image: grafana/grafana:10.1.0
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
deploy:
replicas: 1

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
deploy:
mode: global

volumes:
prometheus-data:
grafana-data:

8 - Organisation et conventions

Nommage

# Services
{app}-{composant}
exemple: myapp-api, myapp-web, myapp-worker

# Réseaux
{app}-{tier}
exemple: myapp-frontend, myapp-backend

# Volumes
{app}-{service}-data
exemple: myapp-db-data, myapp-redis-data

# Secrets
{app}-{service}-{type}
exemple: myapp-db-password, myapp-api-key

Labels

services:
api:
deploy:
labels:
com.example.app: "myapp"
com.example.env: "production"
com.example.team: "backend"
com.example.version: "1.2.3"

Documentation

# Documenter dans le fichier compose
# =====================================================
# MyApp Production Stack
# =====================================================
# Version: 1.2.3
# Maintainer: [email protected]
#
# Prerequisites:
# - Secrets: db_password, jwt_secret
# - Networks: traefik-public (external)
#
# Deployment:
# docker stack deploy -c docker-compose.yml myapp
# =====================================================

version: "3.9"
services:
# ...

9 - Checklist production

Avant déploiement

## Checklist Pré-Déploiement

### Infrastructure
- [ ] 3+ managers configurés
- [ ] Workers labellisés par zone
- [ ] Firewall configuré (ports 2377, 7946, 4789)
- [ ] Autolock activé

### Images
- [ ] Tags versionnés (pas :latest)
- [ ] Scannées pour vulnérabilités
- [ ] Stockées dans un registre privé

### Services
- [ ] Healthchecks définis
- [ ] Limites de ressources définies
- [ ] Rolling update configuré
- [ ] Restart policy définie
- [ ] Réplicas >= 2 pour services critiques

### Réseau
- [ ] Réseaux overlay créés
- [ ] Backend isolé (internal)
- [ ] Chiffrement activé si nécessaire

### Secrets
- [ ] Pas de secrets en clair
- [ ] Secrets créés et documentés
- [ ] Plan de rotation défini

### Monitoring
- [ ] Prometheus/Grafana déployés
- [ ] Alertes configurées
- [ ] Logs centralisés

### Backup
- [ ] Script de backup en place
- [ ] Test de restauration effectué

10 - Erreurs courantes à éviter

Architecture

# ❌ Tous les managers dans la même zone
# ❌ Nombre pair de managers
# ❌ Managers exécutant des workloads

# ✅ Managers répartis géographiquement
# ✅ 3 ou 5 managers
# ✅ Managers en mode drain

Sécurité

# ❌ Secrets dans les variables d'environnement
# ❌ Conteneurs root
# ❌ Réseaux non isolés

# ✅ Docker secrets
# ✅ Utilisateurs non-root
# ✅ Réseaux séparés frontend/backend

Déploiement

# ❌ Images :latest
# ❌ Pas de healthcheck
# ❌ Pas de limites de ressources

# ✅ Tags versionnés
# ✅ Healthchecks sur tous les services
# ✅ Limits et reservations définis

Résumé

CatégorieBonne pratique
Managers3 ou 5, répartis, en mode drain
SécuritéAutolock, secrets, réseaux chiffrés
ImagesTags versionnés, registre privé
DéploiementRolling update, healthchecks
RessourcesLimits et reservations obligatoires
NetworkingIsolation frontend/backend
MonitoringPrometheus + Grafana + alertes
Points clés
  • Séparez les managers des workers
  • Utilisez des secrets, jamais de plaintext
  • Healthchecks sur tous les services
  • Monitoring et alerting obligatoires

Exercices pratiques

  1. Configurez un cluster avec les bonnes pratiques
  2. Créez une stack avec isolation réseau complète
  3. Mettez en place le monitoring avec Prometheus
  4. Testez un rolling update avec zero-downtime

← Haute disponibilité | Exercices et projets →