La planification de capacité dans Docker Compose est la discipline pratique consistant à dimensionner correctement le CPU, la mémoire et les E/S pour chaque service afin que votre pile reste rapide, prévisible et récupérable à mesure que la charge augmente. Ce guide parcourt une boucle complète : inventorier votre environnement, appliquer des limites de ressources sûres dans le format de fichier Compose 2.4, vérifier que les limites sont appliquées, définir des signaux de mise à l'échelle, gérer les modes de défaillance courants et exécuter une liste de contrôle opérationnelle reproductible. Les exemples utilisent Nginx, PostgreSQL et Redis. Tous les nombres marqués comme exemples construits sont des points de départ seulement ; mesurez et affinez pour votre charge de travail.
---
Inventaire de l'environnement et des versions
Avant de modifier les limites, construisez un inventaire court. Vous devez savoir exactement ce que vous dimensionnez et quelles garde-fous l'hôte supporte.
Prérequis :
- OS hôte : Linux, ou Docker Desktop avec un backend Linux
- Docker Engine : 20.10+ (hôtes compatibles cgroups v2 recommandés)
- Plugin Docker Compose : v2.20+ (invoqué comme
docker compose) - Accès sudo pour les commandes système et Docker
Liste de contrôle d'inventaire :
- Enregistrer les versions de Docker Engine et Compose :
docker version,docker compose version - Capacité de l'hôte :
nproc,free -h,lsblk -o NAME,SIZE,TYPE,MOUNTPOINT - Cgroups :
mount | grep cgroup, confirmer que les contrôleurs memory et pids sont activés - Topologie Compose actuelle : services, réseaux, volumes
- Métriques de référence : CPU au repos, empreinte mémoire, latence disque (ex.
iostat -x 1 5)
Conservez cet inventaire dans votre dépôt ou votre runbook afin que les futures modifications référencent une base connue.
---
Chemin de configuration sûr
Pour Docker Compose autonome (non-Swarm), utilisez le format de fichier Compose 2.4 pour appliquer des limites par service directement. Évitez deploy.resources car il est destiné à l'ordonnancement Swarm et peut être ignoré dans Compose non-Swarm.
Options clés dans Compose v2.4 :
cpus: limite CPU fractionnaire par conteneur (ex.0.50)mem_limit: plafond mémoire dur (ex.512m)mem_reservation: réservation mémoire souple indicatrice (ex.384m)pids_limit: nombre maximal de processus par conteneurulimits: descripteurs de fichiers et autres limites par processusshm_size: taille de la mémoire partagée (important pour PostgreSQL)restart: politique de redémarrage du conteneur pour la résiliencehealthcheck: vérifications de vivacité de base pour ordonner les dépendances et vérifier le démarrage
Conseils de sécurité :
- Déployez les limites de manière incrémentale. Préférez commencer par des réservations et des plafonds doux.
- Maintenez 20 à 30 % de marge pendant l'opération normale pour le CPU et la mémoire.
- Changez une variable par itération ; vérifiez avant d'autres modifications.
---
Exemple construit : Nginx, PostgreSQL, Redis
Voici un docker-compose.yml construit utilisant le format de fichier Compose 2.4. Remplacez les versions d'images par celles que vous standardisez. Les nombres sont des points de départ ; ajustez avec des mesures.
version: "2.4"
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
depends_on:
- cache
- db
healthcheck:
test: ["CMD-SHELL", "wget -qO- http://localhost/ || exit 1"]
interval: 10s
timeout: 3s
retries: 5
cpus: "0.50" # point de départ exemple construit
mem_limit: "256m"
mem_reservation: "192m"
pids_limit: 256
ulimits:
nofile:
soft: 65536
hard: 65536
restart: unless-stopped
networks: [appnet]
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: secret
POSTGRES_DB: appdb
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d appdb"]
interval: 10s
timeout: 5s
retries: 10
cpus: "1.00" # point de départ exemple construit
mem_limit: "2g"
mem_reservation: "1g"
shm_size: "512m" # meilleur pour les plans de requête et les tris
pids_limit: 4096
ulimits:
nofile:
soft: 262144
hard: 262144
restart: unless-stopped
networks: [appnet]
cache:
image: redis:7-alpine
command: ["redis-server", "--save", "", "--appendonly", "no"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 10
cpus: "0.50" # point de départ exemple construit
mem_limit: "512m"
mem_reservation: "384m"
pids_limit: 1024
ulimits:
nofile:
soft: 65536
hard: 65536
restart: unless-stopped
networks: [appnet]
networks:
appnet:
driver: bridge
volumes:
pgdata:
Pourquoi ces réglages (rationale construite) :
- web est lié aux E/S et bénéficie d'une marge sur les descripteurs de fichiers. Un CPU et une RAM modestes suffisent à petite échelle.
- db est sensible à la mémoire ; lui donner plus de RAM réduit les E/S en permettant des caches plus grands.
shm_sizeréduit les débordements vers fichiers temporaires lors de gros tris et jointures de hachage. - cache est mono-thread mais sensible à la latence ; CPU 0.5 avec 384–512 Mo RAM fournit une plage de départ sûre.
Résumé des limites de départ construites (à modifier au fur et à mesure) :
| Service | CPU (cpus) | Limite mem | Réservation mem | Limite PIDs | Notes |
|---|---|---|---|---|---|
| web | 0.50 | 256m | 192m | 256 | Augmenter nofile pour connexions concurrentes |
| db | 1.00 | 2g | 1g | 4096 | Plus de RAM réduit E/S disque ; ajouter shm_size |
| cache | 0.50 | 512m | 384m | 1024 | Garder AOF désactivé pour caches sensibles à la latence |
Source : exemple construit pour dimensionnement initial seulement
Monter la pile et confirmer :
# Valider le fichier
docker compose -f docker-compose.yml config
# Démarrer les services
docker compose -f docker-compose.yml up -d
# Lister les conteneurs et leur santé
docker compose ps
Résultat attendu :
- Tous les services affichent
Upavec(healthy)après le passage de leurs vérifications. - L'utilisation CPU et mémoire de l'hôte reste dans une marge sûre.
---
Vérification et diagnostics
1. Confirmer les limites appliquées
# Remplacer <id> par l'ID du conteneur de chaque service
cid_web=$(docker compose ps -q web)
cid_db=$(docker compose ps -q db)
cid_cache=$(docker compose ps -q cache)
# Vérifier les contraintes CPU et mémoire
for c in $cid_web $cid_db $cid_cache; do
echo "Inspection $c";
docker inspect $c --format='Nom: {{.Name}}
NanoCPUs: {{.HostConfig.NanoCpus}}
Memoire: {{.HostConfig.Memory}}
PidsLimit: {{.HostConfig.PidsLimit}}
ShmSize: {{.HostConfig.ShmSize}}
';
done
Résultat attendu :
NanoCpuscorrespond à votrecpusmultiplié par 1e9 (ex. 0.5 → 500000000).Memoireéquivaut aux octets pour votremem_limit(ex. 256m → 268435456).PidsLimitetShmSize(db) correspondent à votre configuration.
2. Observer l'utilisation en temps réel
docker stats --no-stream
Résultat attendu :
MEM USAGE / LIMITreste confortablement sousLIMITpendant l'activité typique.- CPU % flotte sous votre allocation CPU effective en régime permanent.
3. Valider la santé et la disponibilité
# État de santé
docker inspect $cid_web --format='{{json .State.Health}}' | jq .
# Vérification HTTP simple
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080/
Résultat attendu :
- L'état de santé rapporte
healthypour tous les services. curlretourne200depuis web.
4. Diagnostics par les journaux
docker compose logs --since=10m --tail=200
Recherchez les messages OOM, throttling ou retry. Les signaux typiques incluent OOMKilled, réinitialisations de connexion ou blocages d'écriture.
5. Sonde de charge légère (construite)
Vous pouvez simuler une petite rafale pour vérifier que la marge existe :
# 50 requêtes rapides, sérialisées (exemple construit)
for i in $(seq 1 50); do curl -s -o /dev/null -w '.' http://localhost:8080/; done; echo
Résultat attendu :
- Les réponses se terminent rapidement sans pics d'erreurs ou redémarrages de conteneurs.
---
Signaux et limites de mise à l'échelle
Définissez des signaux et seuils clairs qui déclenchent la mise à l'échelle ou le redimensionnement. Ce qui suit sont des nombres d'exemples construits que vous pouvez adopter pour des pilotes et affiner plus tard.
| Signal | Fenêtre cible (construite) | Action | Comment vérifier |
|---|---|---|---|
| Utilisation CPU | ≤ 70% pendant 10+ minutes | Ajouter 0.5 CPU ou 1 réplica (sans état) | docker stats, APM applicatif |
| Marge mémoire | ≥ 25% libre vs limite | Augmenter mem_limit de 25–50% | docker stats, journaux OOM |
| Latence HTTP p99 | ≤ 300 ms stable | Mettre à l'échelle réplicas web/app ; ajuster keepalive | Métriques app, journaux d'accès |
| Latence ops Redis | ≤ 2 ms p99 | Ajouter CPU ou réduire AOF/durabilité | Redis INFO, métriques app |
| Temps checkpoint DB | ≤ 1 min | Augmenter RAM, ajuster WAL/checkpoint | Journaux Postgres, pg_stat_bgwriter |
| Profondeur file | Vidée dans SLA | Mettre à l'échelle workers horizontalement | Métriques app/file |
Source : seuils initiaux construits ; calibrer avec vos SLO
Notes sur les actions :
- Préférez la mise à l'échelle horizontale pour les niveaux sans état ; augmentez les limites par réplica seulement quand l'utilisation montre un throttling CPU ou une pression garbage-collection.
- Pour PostgreSQL, de la RAM supplémentaire surpasse souvent les augmentations CPU jusqu'à ce que l'ensemble de travail tienne mieux en cache.
- Maintenez une marge de sécurité : visez 20–30 % de capacité inutilisée en régime permanent.
Exemple de mise à l'échelle (worker construit) :
Si vous avez un service worker sans état sans ports liés à l'hôte, vous pouvez ajouter des réplicas en toute sécurité :
# Exemple construit : mettre à l'échelle un service worker
# Remplacer 'worker' par votre nom de service réel
docker compose up -d --scale worker=3
Résultat attendu :
- Les nouveaux réplicas rejoignent le même réseau et consomment la même file/sujet.
- Le CPU et la mémoire de l'hôte restent dans la marge. Sinon, revenez en arrière ou ajoutez de la capacité hôte.
---
Modes de défaillance et récupération
Problèmes courants que vous rencontrerez et comment récupérer en toute sécurité.
| Mode de défaillance | Symptôme | Vérification rapide | Récupération |
|---|---|---|---|
| OOM kill | Conteneur redémarre, OOMKilled=true | docker inspect .State.OOMKilled, journaux | Augmenter mem_limit, réduire heap/cache, ou diviser la charge ; redémarrer |
| Throttling CPU | Latence élevée, débit inégal | docker stats CPU % élevé, dmesg throttling CFS | Augmenter cpus, mettre à l'échelle, ou réduire coût par requête |
| Saturation E/S | iowait élevé, écritures DB lentes | iostat -x, checkpoints Postgres lents | Augmenter RAM (cache), déplacer données vers disque plus rapide, ajuster WAL/checkpoint |
| Épuisement descripteurs | Erreurs EMFILE | Journaux app, ulimit -n dans conteneur | Augmenter ulimits.nofile ; redémarrer |
| Limite PIDs atteinte | Échecs fork/exec | docker inspect .HostConfig.PidsLimit | Augmenter pids_limit ; revoir modèle de processus |
| Croissance journaux remplit disque | Disque 100% plein | df -h, taille journaux | Rotater/tronquer journaux, déplacer vers logging externe, plafonner rétention |
Source : entrées runbook construites pour services conteneurisés courants
Étapes de retour arrière et récupération :
- Soulagement immédiat
- Augmenter temporairement
mem_limitoucpuspour le service impacté, puisdocker compose up -dpour appliquer. - Si l'hôte est épuisé, réduire d'abord les services non critiques ou déplacer la charge hors-hôte.
- Configuration connue-bonne
- Revenir au dernier commit compose connu-bon :
git checkout <commit_connu_bon> -- docker-compose.yml
docker compose up -d
- Récupération base de données
- Si PostgreSQL est en récupération après crash, laissez-lui le temps de rejouer le WAL. Si corruption suspectée, restaurer depuis votre dernière sauvegarde vérifiée vers le volume
pgdata.
- Valider la récupération
- Confirmer que les healthchecks sont verts,
docker statsest stable, et les sondes applicatives réussissent.
---
Liste de contrôle opérationnelle
Utilisez cette liste lors des revues de capacité et avant les livraisons qui peuvent changer les patterns de charge.
- Planifier un petit changement pilote inspectable et définir les métriques de succès (nombres construits acceptables pour premier passage) :
- CPU ≤ 70% pour fenêtres stables de 10 minutes
- Marge mémoire ≥ 25%
- Latence p99 dans votre SLO
- Inventorier l'environnement et les bases :
- Enregistrer versions Docker/Compose, CPU/RAM/disque hôte
- Capturer
docker stats --no-streampour tous les services - Appliquer les limites sûrement (Compose v2.4) :
- Définir
cpus,mem_limit,mem_reservation,pids_limit, etulimits - Ajouter
healthchecket politiquesrestart - Monter et vérifier :
docker compose up -d,docker compose psdocker inspectpour confirmerNanoCPUs/Memory/PIDsdocker statspour usage vs limites- Tests de fumée applicatifs (HTTP 200, cache PING, DB prêt)
- Exercice de charge légère :
- Exécuter une petite rafale et observer
docker stats, journaux, et latence - Décider de l'étape suivante :
- Si marge adéquate, conserver limites et documenter
- Si contraint, ajuster une limite ou ajouter un réplica ; répéter la vérification
- Documenter les décisions :
- Enregistrer limites finales, utilisation observée, et rationale
- Noter chemin de retour arrière et état des sauvegardes
- Planifier une revue de suivi :
- Re-vérifier après heures de pointe ou lancements de fonctionnalités majeures
---
Conclusion
La planification de capacité Compose est une boucle reproductible : poser des garde-fous, vérifier, observer, et ajuster. Commencez avec un pilote étroit facile à inspecter, préférez des limites simples et explicites dans Compose v2.4, et gardez une trace claire des métriques de base et des décisions. Avec de petites itérations sûres et des signaux bien définis, vous pouvez mettre à l'échelle les services de manière prévisible tout en préservant les marges de sécurité opérationnelles. Le but n'est pas une configuration statique parfaite mais un processus discipliné qui vous laisse répondre aux patterns de charge réels sans devinettes ni lutte contre les incendies d'urgence.