Limites de mémoire et de CPU pour les conteneurs
Comment fixer un plafond de mémoire et de CPU pour un conteneur, pourquoi sans cela un service fait tomber tous les autres, et comment savoir qu'un processus a été tué par le noyau.
Mis à jour le 23 août 2026
Par défaut, un conteneur peut prendre toute la mémoire et tous les cœurs de la machine. Sur VDS-1 avec deux gigaoctets, cela se termine de façon prévisible : un service gonfle, le noyau commence à tuer des processus, et ce qui tombe n'est pas lui mais la base de données à côté.
Comment fixer un plafond
services:
app:
image: ghcr.io/example/app:1.5.0
deploy:
resources:
limits:
memory: 768M
cpus: "1.0"
reservations:
memory: 256M
Compose applique deploy.resources.limits même avec un simple docker compose up -d. L'équivalent pour docker run :
docker run -d --memory 768m --cpus 1.0 --memory-swap 768m <image>
Définir --memory-swap égal à --memory interdit le swap : un crash honnête vaut mieux qu'une machine qui avance à peine pendant des heures.
Quelle quantité allouer
Partez de votre palier et laissez un peu de marge au système.
| Palier | Mémoire | Plafond total raisonnable des conteneurs |
|---|---|---|
| VDS-1 | 2 GB | jusqu'à 1.5 GB |
| VDS-2 | 4 GB | jusqu'à 3 GB |
| VDS-3 | 8 GB | jusqu'à 6.5 GB |
| VDS-4 | 16 GB | jusqu'à 14 GB |
| VDS-5 | 24 GB | jusqu'à 21 GB |
| VDS-6 | 32 GB | jusqu'à 29 GB |
Le reste est nécessaire au système, au cache de fichiers et à Docker lui-même. Une somme de limites supérieure à la quantité de mémoire n'est pas une erreur de configuration — c'est un désastre qui attend son heure.
Pour le CPU : cpus: "1.0" correspond à un cœur complet. VDS-1 n'a qu'un seul cœur, il est donc peu utile d'y limiter le CPU, mais sur VDS-4 et au-delà, il vaut la peine d'empêcher la configuration de serveur de prendre les six.
Ce qui est réellement consommé
docker stats --no-stream
docker stats --no-stream --format "table {{.Name}}\t{{.MemUsage}}\t{{.CPUPerc}}"
free -h
Surveillez le service pendant une journée sous charge et fixez la limite à environ une fois et demie le pic. Une limite trop stricte est pire que pas de limite du tout : le service redémarrera au moment où vous en avez le plus besoin.
htopetbtopen plein écran ne fonctionnent que dans la console « Screen » (VNC). La console texte ne transmet pas la taille de la fenêtre, elle fait toujours 80×24, et l'interface s'effondre. Pour des mesures rapides dans la console texte, utilisezdocker stats --no-streametfree -h.
Comment savoir que la mémoire est responsable
docker inspect -f '{{.State.ExitCode}} {{.State.OOMKilled}}' <container>
sudo dmesg -T | grep -i -E "out of memory|killed process"
Le code de sortie 137 accompagné de OOMKilled: true est un verdict sans ambiguïté. À partir de là, vous avez deux options : relever la limite si elle était trop basse, ou comprendre pourquoi l'application ne cesse de grossir — une fuite ne se soigne pas en ajoutant de la mémoire, elle est seulement repoussée.
Java et autres cas particuliers
La machine virtuelle Java voit encore parfois la mémoire de l'hôte plutôt que la limite du conteneur, et dimensionne le tas avec une marge qui n'existe pas. Définissez-la explicitement :
environment:
JAVA_TOOL_OPTIONS: "-Xmx512m -Xms256m"
Il en va de même pour PostgreSQL (shared_buffers) et tout service disposant de son propre pool.
Erreurs courantes
- Aucune limite définie. La cause la plus fréquente de « la machine s'est figée, rien ne répond ».
- La limite est là, mais il n'y a pas de health check. Le conteneur a été tué et n'a jamais redémarré. Ajoutez
restart: unless-stoppedet unhealthcheck— voir mise à jour des conteneurs. - Vous avez oublié le disque. Vous avez limité la mémoire, mais les écritures se heurtent à un plafond : voir vitesse du disque.