Déploiement en production avec Docker Compose : 7 stratégies clés des health checks aux mises à jour sans interruption
« Ça marche sur ma machine » — Le cimetière des conteneurs en production
Le mantra de chaque développeur : « Ça marche sur ma machine. » Mais quand les conteneurs arrivent en production, le vrai cauchemar commence :
- Conteneurs silencieusement OOM Killed, ne laissant que
Out of memorydans les logs - Base de données pas encore prête, conteneurs d'application criant
Connection refused - Conteneur plante à 3h du matin sans politique de redémarrage — service hors ligne jusqu'au matin
- Fichiers de logs remplissant les disques,
docker logsaffichant des dizaines de Go de texte non structuré - Identifiants de production en clair dans
docker-compose.yml, mots de passe de base de données exposés
Si vous utilisez encore docker compose up -d comme toute votre stratégie de production, cet article est pour vous.
Référence des concepts clés
| Concept | Objectif | Configuration clé en production |
|---|---|---|
| Health Check | Détecter si un conteneur est vraiment prêt | healthcheck + depends_on.condition |
| Limites de ressources | Limiter CPU/mémoire, prévenir la surconsommation | deploy.resources.limits |
| Politique de redémarrage | Redémarrage automatique en cas de sortie anormale | deploy.restart_policy |
| Secrets | Stockage chiffré des données sensibles | secrets + Docker Secret |
| Pilote de logging | Logging structuré + rotation des logs | logging.driver + logging.options |
| Profiles | Démarrage sélectif des services par environnement | profiles |
| Watch | Synchronisation automatique des modifications de fichiers vers les conteneurs | watch (Compose Watch) |
5 Défis de production
Défi 1 : Ordre de démarrage des conteneurs incontrôlable
La base de données est encore en cours d'initialisation pendant que le conteneur d'application tente de se connecter, causant des échecs de démarrage. depends_on garantit seulement l'ordre de démarrage, pas la disponibilité du service.
Défi 2 : Expansion illimitée des ressources
Les conteneurs sans limites de ressources sont comme des voitures sans freins. Un seul conteneur avec une fuite mémoire peut consommer toute la mémoire de l'hôte et faire tomber tous les services.
Défi 3 : Le trou noir des logs
Le pilote de logs json-file par défaut ne fait pas de rotation. Après 3 mois d'exécution, /var/lib/docker remplit le disque et tous les services plantent.
Défi 4 : Exposition de données sensibles
Mots de passe de base de données en clair dans les blocs environment, fichiers .env commités dans Git, clés API codées en dur dans les images — ce sont des bombes à retardement pour les incidents de production.
Défi 5 : Les mises à jour signifient un temps d'arrêt
docker compose up -d arrête les anciens conteneurs avant d'en démarrer de nouveaux par défaut, rendant le service indisponible pendant les mises à jour. Pour les services 24/7, c'est inacceptable.
7 Patterns de production
Pattern 1 : Health checks et ordonnancement des dépendances
Problème : depends_on contrôle seulement l'ordre de démarrage, ne garantit pas la disponibilité du service.
Solution : Utiliser healthcheck + depends_on.condition: service_healthy.
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
volumes:
- postgres_data:/var/lib/postgresql/data
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
app:
image: myapp:latest
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
ports:
- "3000:3000"
Paramètres clés :
interval: Intervalle de vérification, 5-10 secondes recommandées pour la productiontimeout: Délai d'attente d'une vérification, 3-5 secondes recommandéesretries: Échecs consécutifs avant de marquer comme unhealthystart_period: Période de grâce après le démarrage du conteneur, les échecs ne comptent pas
Pattern 2 : Limites de ressources et protection OOM
Problème : Les conteneurs sans limites se disputent les ressources de l'hôte. Un conteneur incontrôlé peut faire tomber toute la machine.
Solution : Utiliser deploy.resources pour définir les limites et réservations de CPU et mémoire.
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
worker:
image: myworker:latest
deploy:
resources:
limits:
cpus: '1.0'
memory: 1G
reservations:
memory: 512M
Limites vs Réservations :
limits: Plafond strict, dépassé → OOM Kill ou throttling CPUreservations: Garantie souple, l'ordonnanceur essaie de respecter mais n'impose pas
Stratégie de protection OOM :
services:
critical-service:
image: critical-app:latest
deploy:
resources:
limits:
memory: 1G
cap_add:
- SYS_PTRACE
Au niveau de l'hôte, configurez vm.overcommit_memory et ajustez les politiques OOM :
# Vérifier le score OOM du conteneur
docker inspect --format='{{.State.OOMKilled}}' <container_id>
# Définir la politique OOM de l'hôte : ne pas tuer les processus critiques
echo -1000 > /proc/<pid>/oom_score_adj
Pattern 3 : Logging structuré et rotation des logs
Problème : Le pilote de logs json-file par défaut ne fait pas de rotation ; les disques se remplissent avec le temps.
Solution : Configurer le pilote de logs + la politique de rotation. Le pilote local est recommandé pour la production.
services:
app:
image: myapp:latest
logging:
driver: local
options:
max-size: "10m"
max-file: "5"
tag: "{{.Name}}/{{.ID}}"
nginx:
image: nginx:1.27-alpine
logging:
driver: json-file
options:
max-size: "50m"
max-file: "10"
tag: "nginx/{{.Name}}"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
Comparaison des pilotes de logs :
| Pilote | Cas d'utilisation | Avantages | Inconvénients |
|---|---|---|---|
| local | Valeur par défaut en production | Auto-rotation, stockage compressé | Local uniquement |
| json-file | Logs JSON structurés nécessaires | Support natif Docker | Configuration manuelle de rotation requise |
| syslog | Collecte centralisée des logs | Peut envoyer à distance | Configuration complexe |
| fluentd | Intégration stack EFK | Routage flexible des logs | Nécessite le déploiement de Fluentd |
Logging structuré au niveau applicatif :
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
ENV TZ=UTC
ENV LOG_FORMAT=json
CMD ["node", "server.js"]
const logger = {
info: (msg, meta = {}) => {
console.log(JSON.stringify({ level: 'info', msg, ts: new Date().toISOString(), ...meta }));
},
error: (msg, meta = {}) => {
console.error(JSON.stringify({ level: 'error', msg, ts: new Date().toISOString(), ...meta }));
}
};
Pattern 4 : Gestion des Secrets
Problème : Données sensibles stockées en clair dans les fichiers compose ou les variables d'environnement.
Solution : Docker Secrets + variables d'environnement avec suffixe _FILE.
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
file: ./secrets/api_key.txt
jwt_secret:
file: ./secrets/jwt_secret.txt
services:
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
app:
image: myapp:latest
environment:
DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/appdb
API_KEY_FILE: /run/secrets/api_key
JWT_SECRET_FILE: /run/secrets/jwt_secret
secrets:
- api_key
- jwt_secret
Gestion des fichiers de secrets :
# Créer le répertoire des secrets
mkdir -p secrets
chmod 700 secrets
# Écrire les fichiers de secrets
echo "my-super-secret-password-2026" > secrets/db_password.txt
echo "ak-live-xxxx-yyyy-zzzz" > secrets/api_key.txt
echo "jwt-hs256-secret-key-here" > secrets/jwt_secret.txt
# Définir les permissions : lisible uniquement par root
chmod 600 secrets/*.txt
.gitignore doit inclure :
secrets/
*.secret
.env.production
.env.staging
Comparaison Docker Secrets vs .env :
| Fonctionnalité | Docker Secrets | Fichiers .env |
|---|---|---|
| Stockage chiffré | Oui (en mode Swarm) | Non |
| Permissions de fichiers | Restreintes (/run/secrets/) | Dépend du système de fichiers |
| Piste d'audit | Oui | Non |
| Synchronisation inter-nœuds | Swarm synchronise automatiquement | Distribution manuelle |
| Cas d'utilisation | Swarm/production mono-hôte | Développement |
Pattern 5 : Mises à jour rolling sans interruption
Problème : docker compose up -d arrête les anciens conteneurs avant d'en démarrer de nouveaux par défaut.
Solution : Utiliser docker compose up --no-down + health checks + proxy inverse.
services:
app:
image: myapp:${APP_VERSION:-latest}
deploy:
replicas: 2
update_config:
parallelism: 1
delay: 10s
order: start-first
failure_action: rollback
rollback_config:
parallelism: 0
order: stop-first
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 5s
timeout: 3s
retries: 3
start_period: 15s
labels:
- "com.toolsku.app=true"
ports:
- "3000-3001:3000"
nginx:
image: nginx:1.27-alpine
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
app:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:80/health"]
interval: 10s
timeout: 3s
retries: 3
Configuration du proxy inverse Nginx :
upstream app_backend {
server app:3000;
}
server {
listen 80;
server_name app.example.com;
location / {
proxy_pass http://app_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_next_upstream error timeout http_502 http_503;
}
location /health {
access_log off;
return 200 'ok';
add_header Content-Type text/plain;
}
}
Script de mise à jour sans interruption :
#!/bin/bash
set -euo pipefail
NEW_IMAGE="myapp:v2.0.0"
echo "🚀 Démarrage de la mise à jour sans interruption vers ${NEW_IMAGE}"
# 1. Tirer la nouvelle image
docker compose pull app
# 2. Démarrer les nouveaux conteneurs (sans arrêter les anciens)
docker compose up -d --no-deps --scale app=2 app
# 3. Attendre que les nouveaux conteneurs soient sains
echo "⏳ Attente de la santé des nouveaux conteneurs..."
sleep 15
# 4. Vérifier la santé du nouveau conteneur
for i in $(seq 1 30); do
if curl -sf http://localhost:3000/health > /dev/null 2>&1; then
echo "✅ Le nouveau conteneur est sain"
break
fi
if [ $i -eq 30 ]; then
echo "❌ Health check échoué, retour en arrière..."
docker compose up -d --no-deps --scale app=1 app
exit 1
fi
sleep 2
done
# 5. Réduire à 1 réplique
docker compose up -d --no-deps --scale app=1 app
echo "🎉 Mise à jour terminée avec succès"
Pattern 6 : Stack de monitoring Prometheus + Grafana
Problème : Faire tourner la production sans monitoring, c'est voler à l'aveugle — vous n'apprenez les problèmes que par les plaintes des utilisateurs.
Solution : Déployer un stack complet de monitoring Prometheus + Grafana.
services:
prometheus:
image: prom/prometheus:v2.52.0
container_name: prometheus
restart: unless-stopped
ports:
- "9090:9090"
volumes:
- ./monitoring/prometheus.yml:/etc/prometheus/prometheus.yml:ro
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.retention.time=30d'
- '--storage.tsdb.retention.size=5GB'
deploy:
resources:
limits:
memory: 512M
networks:
- monitoring
grafana:
image: grafana/grafana:11.0.0
container_name: grafana
restart: unless-stopped
ports:
- "3001:3000"
environment:
GF_SECURITY_ADMIN_USER: admin
GF_SECURITY_ADMIN_PASSWORD_FILE: /run/secrets/grafana_password
secrets:
- grafana_password
volumes:
- grafana_data:/var/lib/grafana
deploy:
resources:
limits:
memory: 256M
depends_on:
- prometheus
networks:
- monitoring
node-exporter:
image: prom/node-exporter:v1.8.0
container_name: node-exporter
restart: unless-stopped
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--path.rootfs=/rootfs'
networks:
- monitoring
alertmanager:
image: prom/alertmanager:v0.27.0
container_name: alertmanager
restart: unless-stopped
ports:
- "9093:9093"
volumes:
- ./monitoring/alertmanager.yml:/etc/alertmanager/alertmanager.yml:ro
networks:
- monitoring
secrets:
grafana_password:
file: ./secrets/grafana_password.txt
volumes:
prometheus_data:
grafana_data:
networks:
monitoring:
driver: bridge
Configuration de Prometheus :
# monitoring/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "alert_rules.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: 'node-exporter'
static_configs:
- targets: ['node-exporter:9100']
- job_name: 'app'
static_configs:
- targets: ['app:3000']
metrics_path: /metrics
Règles d'alerte :
# monitoring/alert_rules.yml
groups:
- name: container_alerts
rules:
- alert: ContainerDown
expr: up == 0
for: 1m
labels:
severity: critical
annotations:
summary: "Container {{ $labels.instance }} is down"
- alert: HighMemoryUsage
expr: process_resident_memory_bytes / (1024 * 1024) > 400
for: 5m
labels:
severity: warning
annotations:
summary: "Memory usage exceeds 400MB on {{ $labels.instance }}"
- alert: DiskSpaceLow
expr: node_filesystem_avail_bytes / node_filesystem_size_bytes < 0.1
for: 5m
labels:
severity: critical
annotations:
summary: "Disk space below 10% on {{ $labels.instance }}"
Pattern 7 : Configuration multi-environnement (dev/staging/prod)
Problème : Les configurations dev, staging et production sont mélangées — modifier la configuration d'un environnement risque d'affecter les autres.
Solution : Utiliser docker-compose.override.yml + stratégie de superposition multi-fichiers.
Structure de répertoires :
project/
├── docker-compose.yml # Configuration de base
├── docker-compose.override.yml # Surcharge dev (chargée automatiquement)
├── docker-compose.staging.yml # Surcharge staging
├── docker-compose.prod.yml # Surcharge production
├── .env # Variables d'environnement par défaut
├── .env.staging # Variables d'environnement staging
├── .env.prod # Variables d'environnement production
├── monitoring/
│ ├── prometheus.yml
│ └── alertmanager.yml
└── secrets/
├── db_password.txt
├── api_key.txt
└── grafana_password.txt
Configuration de base docker-compose.yml :
services:
app:
image: myapp:${APP_VERSION:-latest}
environment:
NODE_ENV: ${NODE_ENV:-development}
DATABASE_URL: postgresql://appuser:${DB_PASSWORD}@postgres:5432/appdb
REDIS_URL: redis://redis:6379
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- app-network
postgres:
image: postgres:16-alpine
environment:
POSTGRES_DB: appdb
POSTGRES_USER: appuser
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-network
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- app-network
secrets:
db_password:
file: ./secrets/db_password.txt
volumes:
postgres_data:
networks:
app-network:
driver: bridge
Surcharge dev docker-compose.override.yml (chargée automatiquement) :
services:
app:
build: .
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
- "9229:9229"
environment:
NODE_ENV: development
LOG_LEVEL: debug
deploy:
resources:
limits:
memory: 512M
command: node --inspect=0.0.0.0:9229 server.js
adminer:
image: adminer:latest
ports:
- "8080:8080"
networks:
- app-network
Surcharge production docker-compose.prod.yml :
services:
app:
image: myapp:${APP_VERSION}
ports:
- "3000:3000"
environment:
NODE_ENV: production
LOG_LEVEL: info
deploy:
replicas: 2
resources:
limits:
cpus: '2.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
logging:
driver: local
options:
max-size: "10m"
max-file: "5"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 15s
postgres:
deploy:
resources:
limits:
cpus: '2.0'
memory: 2G
reservations:
memory: 1G
logging:
driver: local
options:
max-size: "50m"
max-file: "10"
redis:
deploy:
resources:
limits:
memory: 512M
command: redis-server --appendonly yes --maxmemory 400mb --maxmemory-policy allkeys-lru
volumes:
- redis_data:/data
logging:
driver: local
options:
max-size: "10m"
max-file: "3"
nginx:
image: nginx:1.27-alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.prod.conf:/etc/nginx/nginx.conf:ro
depends_on:
app:
condition: service_healthy
deploy:
resources:
limits:
memory: 128M
logging:
driver: local
options:
max-size: "50m"
max-file: "10"
volumes:
redis_data:
Commandes de démarrage :
# Développement (charge l'override automatiquement)
docker compose up -d
# Staging
docker compose -f docker-compose.yml -f docker-compose.staging.yml --env-file .env.staging up -d
# Production
docker compose -f docker-compose.yml -f docker-compose.prod.yml --env-file .env.prod up -d
5 Pièges courants
Piège 1 : depends_on ne signifie pas que le service est prêt
❌ Faux :
services:
app:
depends_on:
- postgres
# Le conteneur postgres a démarré, mais la BDD peut ne pas être encore initialisée
✅ Correct :
services:
app:
depends_on:
postgres:
condition: service_healthy
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U appuser -d appdb"]
interval: 5s
timeout: 3s
retries: 5
start_period: 10s
Piège 2 : Pas de limites de ressources
❌ Faux :
services:
app:
image: myapp:latest
# Sans limites de ressources — une fuite mémoire peut consommer tout l'hôte
✅ Correct :
services:
app:
image: myapp:latest
deploy:
resources:
limits:
cpus: '2.0'
memory: 512M
reservations:
cpus: '0.25'
memory: 128M
Piège 3 : Pas de rotation des logs
❌ Faux :
services:
app:
image: myapp:latest
# Pilote json-file par défaut, les logs grandissent indéfiniment
✅ Correct :
services:
app:
image: myapp:latest
logging:
driver: local
options:
max-size: "10m"
max-file: "5"
Piège 4 : Données sensibles en clair
❌ Faux :
services:
postgres:
environment:
POSTGRES_PASSWORD: "my-secret-password-123"
# Mot de passe en clair dans le fichier compose — catastrophe si commité dans Git
✅ Correct :
services:
postgres:
environment:
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
secrets:
- db_password
secrets:
db_password:
file: ./secrets/db_password.txt
Piège 5 : Utiliser le tag latest
❌ Faux :
services:
app:
image: myapp:latest
# Chaque pull peut obtenir une image différente — non reproductible
✅ Correct :
services:
app:
image: myapp:2.1.0
# Ou utiliser une variable pour le contrôle de version
image: myapp:${APP_VERSION:-2.1.0}
Référence de résolution d'erreurs
| Message d'erreur | Cause | Solution |
|---|---|---|
OOMKilled |
Le conteneur a dépassé la limite mémoire | Augmenter la limite memory ou optimiser l'utilisation mémoire de l'app |
Connection refused |
Service dépendant non prêt | Ajouter healthcheck + depends_on.condition |
no space left on device |
Logs/images remplissant le disque | Configurer la rotation logging + docker system prune |
Boucle de restarting |
L'application plante au démarrage | Vérifier docker logs <id> et confirmer la configuration |
permission denied |
Problème de permissions de fichier/répertoire | Vérifier la directive user et les permissions des volumes |
port is already allocated |
Conflit de port | Changer le mappage de port ou arrêter le processus en conflit |
Statut unhealthy |
Health check en échec | Vérifier que la commande healthcheck est correcte |
secret not found |
Fichier secret manquant | S'assurer que le fichier correspondant existe dans secrets/ |
Cannot connect to the Docker daemon |
Docker n'est pas en cours d'exécution | systemctl start docker |
image pulling failed |
Échec du pull d'image | Vérifier le réseau/authentification du registry/orthographe du nom d'image |
Optimisation avancée
Docker Compose Watch pour le développement
Compose Watch synchronise automatiquement les modifications de fichiers vers les conteneurs sans reconstruire les images :
services:
app:
build: .
develop:
watch:
- action: sync
path: ./src
target: /app/src
- action: rebuild
path: ./package.json
- action: sync+restart
path: ./config
target: /app/config
# Démarrer le mode watch
docker compose watch
Isolation réseau et sécurité
services:
app:
networks:
- frontend
- backend
postgres:
networks:
- backend
# postgres pas dans le réseau frontend — accès externe bloqué
nginx:
networks:
- frontend
ports:
- "80:80"
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
# internal:true désactive l'accès externe
Optimisation d'images avec les builds multi-étapes
# ---- Étape de build ----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# ---- Étape d'exécution ----
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup -g 1001 -S appgroup && \
adduser -S appuser -u 1001 -G appgroup
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER appuser
EXPOSE 3000
HEALTHCHECK --interval=10s --timeout=3s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
CMD ["node", "dist/server.js"]
Comparaison des outils d'orchestration
| Fonctionnalité | Docker Compose | Kubernetes | Nomad | Docker Swarm |
|---|---|---|---|---|
| Complexité | Faible | Élevée | Moyenne | Faible |
| Déploiement mono-hôte | ✅ Excellent | ❌ Excessif | ⚠️ Utilisable | ✅ Excellent |
| Orchestration multi-hôtes | ❌ Non supporté | ✅ Capacité centrale | ✅ Capacité centrale | ⚠️ Basique |
| Auto-scaling | ❌ | ✅ HPA/VPA | ✅ | ⚠️ Manuel |
| Mises à jour rolling | ⚠️ Nécessite des scripts | ✅ Natif | ✅ Natif | ✅ Natif |
| Service discovery | ⚠️ DNS | ✅ CoreDNS | ✅ Consul | ✅ DNS |
| Orchestration du stockage | ❌ | ✅ CSI | ✅ CSI | ⚠️ Basique |
| Courbe d'apprentissage | Faible | Élevée | Moyenne | Faible |
| Échelle adaptée | 1-10 services | 100+ services | 50+ services | 10-50 services |
| Prêt pour la production | ✅ Mono-hôte | ✅ Grande échelle | ✅ Moyenne à grande échelle | ⚠️ Communauté en déclin |
Recommandation : Utilisez Docker Compose pour la production mono-hôte/petite échelle, Kubernetes pour la grande échelle, Nomad si vous êtes dans l'écosystème HashiCorp. Docker Swarm est de plus en plus marginalisé — non recommandé pour les nouveaux projets.
Résumé
Le déploiement en production avec Docker Compose n'est pas juste
docker compose up -d. Les health checks garantissent que les services sont vraiment prêts, les limites de ressources préviennent les avalanches OOM, la rotation des logs évite l'épuisement du disque, les Secrets protègent les données sensibles, les mises à jour sans interruption garantissent la disponibilité 24/7, les stacks de monitoring éliminent les angles morts, et les configurations multi-environnement gardent dev/staging/prod correctement séparés. Maîtrisez ces 7 stratégies, et Docker Compose est tout à fait capable de déploiements en production à petite et moyenne échelle.
Outils recommandés
- Formateur JSON - Formater les configurations JSON liées à Docker Compose YAML
- Encodage Base64 - Encoder les Secrets et données de configuration sensibles
- Calculateur de hachage - Générer des sommes de contrôle pour les fichiers de configuration et assurer la cohérence des déploiements
Essayez ces outils exécutés localement dans le navigateur — aucune inscription requise →