raatools/

Planificateur RAM Docker

Planifiez l'utilisation mémoire des conteneurs par rapport à votre RAM disponible.

Ajouter un conteneur

Services

Custom

RAM Usage 12.5%

RAM totale utilisée

0 MB

Restant

3584 MB

Réservé au système

512 MB

Fits comfortably

Good headroom for scaling and memory spikes.

Qu'est-ce qu'un calculateur de RAM Docker ?

Un calculateur de RAM Docker aide à dimensionner les limites mémoire de vos conteneurs Docker afin d'éviter à la fois le sur-provisionnement (coûteux) et le sous-provisionnement (qui cause des OOM kills). Il permet aussi d'estimer la mémoire totale nécessaire à un déploiement multi-conteneurs.

Une mauvaise allocation de RAM est l'une des principales causes d'incidents en production avec Docker. Les conteneurs peuvent être tués par le kernel (OOMKilled) ou ralentir leur hôte. Cet outil aide à planifier le dimensionnement avant de déployer.

Comment utiliser cet outil

Saisissez le nombre de conteneurs, la mémoire moyenne par conteneur, la marge de sécurité souhaitée et la RAM disponible sur l'hôte. L'outil indique si votre configuration est viable et suggère des ajustements (réduction du nombre, augmentation de la RAM, optimisation des images).

Limites mémoire vs. réservations mémoire

Docker vous offre deux paramètres distincts pour contrôler la quantité de RAM qu'un conteneur peut utiliser : les limites mémoire et les réservations mémoire. Ces deux notions sont souvent confondues, mais elles répondent à des objectifs très différents.

Une limite mémoire (définie avec --memory ou mem_limit dans un fichier Compose) est un plafond absolu. Docker l'applique via le sous-système cgroups du noyau Linux. Le conteneur ne peut jamais allouer plus que cette valeur — s'il tente de le faire, le mécanisme OOM killer du noyau Linux intervient.

  • --memory / mem_limit : la borne haute stricte. Le conteneur ne peut pas la dépasser. Utilisée pour protéger l'hôte contre les processus incontrôlés.
  • --memory-reservation / mem_reservation : une indication souple pour l'ordonnanceur. L'ordonnanceur Docker Swarm s'en sert pour décider où placer les services. Cela n'empêche PAS le conteneur d'utiliser davantage de mémoire — il s'agit simplement d'une garantie minimale que Docker s'efforce de respecter.
  • Bonne pratique courante : fixer la réservation à l'empreinte mémoire attendue au repos et la limite au maximum que vous êtes prêt à autoriser. Par exemple, un conteneur qui utilise 200 MB au repos mais peut monter à 600 MB lors de pics peut être configuré avec reservation=200m et limit=600m.

Si vous omettez les deux paramètres, le conteneur n'a aucune limite et peut consommer toute la RAM disponible sur l'hôte. Sur un serveur dédié à un seul usage, cela peut être acceptable, mais sur un homelab exécutant de nombreux services, c'est un risque considérable.

Que se passe-t-il quand un conteneur atteint sa limite mémoire

Lorsque l'utilisation mémoire d'un conteneur atteint la valeur définie par --memory, le mécanisme OOM (Out of Memory) du noyau Linux tue le processus le plus gourmand en mémoire à l'intérieur du conteneur. Docker enregistre cela sous le code de sortie 137 — une terminaison standard par le signal POSIX 9 (SIGKILL). Vous verrez cela dans docker ps --all ou les logs du conteneur sous la forme « Exited (137) ».

Le code de sortie 137 ne signifie pas que votre application a planté à cause d'un bogue — il signifie que le noyau l'a tuée de force parce que le conteneur a atteint le plafond RAM que vous avez configuré. Si vous observez des sorties 137 répétées dans une application stable, votre limite mémoire est trop basse, ou la charge de travail a dépassé l'estimation initiale. Augmentez la limite et surveillez à nouveau avec docker stats.

Considérations mémoire propres aux runtimes

Les différents runtimes de langage et moteurs de base de données gèrent la mémoire de manière très différente. Définir une limite mémoire pour un conteneur sans tenir compte du comportement du runtime est l'une des causes les plus fréquentes de kills OOM inattendus.

  • JVM (Java, Kotlin, Scala) : la JVM alloue un tas (heap) dès le démarrage. Sans paramètres explicites, elle peut s'approprier une large fraction de la RAM système disponible. Définissez toujours -Xmx (taille maximale du tas) à une valeur inférieure à votre limite mémoire Docker — une règle courante est de laisser au moins 25 % de marge au-dessus de -Xmx pour la mémoire hors-tas, la surcharge du ramasse-miettes et les bibliothèques natives.
  • Node.js : V8 dispose d'une limite de tas par défaut (environ 1,5 GB sur les systèmes 64 bits pour les anciennes versions). Si votre limite Docker est inférieure, le processus peut être tué par OOM avant même que V8 déclenche le ramasse-miettes. Utilisez --max-old-space-size (en MB) pour plafonner le tas old-generation de V8 et fixez-le en dessous de la limite mémoire Docker.
  • Bases de données (PostgreSQL, MariaDB, MySQL) : les bases de données sont par conception des consommatrices agressives de mémoire — elles mettent en cache les pages fréquemment accédées dans leur pool de tampons partagés. La valeur par défaut de shared_buffers dans PostgreSQL est de 128 MB, mais elle est généralement ajustée à 25 % de la RAM disponible pour les serveurs dédiés. Dans un conteneur, ajustez shared_buffers pour qu'il tienne dans votre limite mémoire, sinon la base de données sera tuée de façon inattendue sous charge.
  • Serveurs multimédia (Jellyfin, Plex) : le transcodage est très gourmand en mémoire. Un seul transcodage 4K peut nécessiter 1 à 3 GB en plus de l'empreinte au repos. Si vous activez le transcodage accéléré par matériel, la situation mémoire change considérablement. Vérifiez l'utilisation réelle de votre serveur sous charge réelle avant de finaliser les limites.

Tailles typiques par technologie

Les valeurs ci-dessous sont des plages de départ approximatives à des fins de planification uniquement — l'utilisation réelle varie considérablement selon la configuration, la taille des données, le nombre d'utilisateurs et les fonctionnalités activées. Mesurez toujours avec docker stats après avoir exécuté votre charge de travail réelle.

  • Nginx — 10 à 50 Mo.
  • Node.js — 100 à 500 Mo selon le code.
  • Java/Spring — 512 Mo à 2 Go.
  • PostgreSQL — 256 Mo à plusieurs Go selon la charge.
  • Plex/Jellyfin : 1 à 4 GB selon le transcodage et la taille de la bibliothèque.
  • Proxies inverses légers (Traefik, Caddy, Nginx) : généralement 30 à 150 MB au repos ; ce sont parmi les services les plus économes en mémoire que vous puissiez exécuter.
  • Stacks de monitoring (Prometheus + Grafana) : Prometheus évolue en fonction du nombre de séries temporelles collectées et conservées, de quelques centaines de MB jusqu'à plusieurs GB pour les grands environnements. Grafana lui-même est relativement léger, environ 100 à 300 MB.

Exemple de dimensionnement : un homelab typique sur Raspberry Pi 4 (8 GB)

Pour voir comment l'allocation RAM s'accumule, considérons un Raspberry Pi 4 avec 8 GB exécutant une petite pile auto-hébergée :

  • OS hôte (Raspberry Pi OS Lite) : environ 300 à 500 MB réservés pour le noyau, les processus système et le moteur Docker lui-même
  • Pi-hole (bloqueur de publicités DNS) : limite 128 MB — service léger, faible surcharge
  • Vaultwarden (gestionnaire de mots de passe compatible Bitwarden) : limite 128 MB — binaire Rust très léger
  • Home Assistant : limite 512 MB — basé sur Python, augmente avec les automatisations et les intégrations
  • Jellyfin (serveur multimédia, transcodage logiciel désactivé) : limite 1024 MB — évolue avec la taille de la bibliothèque
  • Portainer (interface de gestion des conteneurs) : limite 256 MB

En additionnant ces limites : 500 (hôte) + 128 + 128 + 512 + 1024 + 256 = environ 2,5 GB alloués. Sur un appareil de 8 GB, il reste environ 5,5 GB de marge — un coussin confortable pour le cache, les pics et les futurs conteneurs. Sur un Pi 4 de 2 GB, cette même pile serait surprovisionnée avant même de considérer les pics. La calculatrice ci-dessus effectue exactement ce type d'arithmétique pour toute combinaison de services que vous choisissez.

Pourquoi le surprovisionnement de RAM est risqué

Le surprovisionnement consiste à planifier une pile dont les limites mémoire combinées dépassent la RAM physique disponible pour l'OS hôte. Docker lui-même ne l'empêche pas — il accepte parfaitement un fichier Compose qui alloue 10 GB sur plusieurs conteneurs sur une machine de 4 GB. Le risque se matérialise à l'exécution : lorsque l'utilisation réelle sur tous les conteneurs approche la RAM physique, le noyau commence à swapper de manière agressive. Le swap sur cartes SD et clés USB (stockage courant dans les homelabs) est des ordres de grandeur plus lent que la RAM et peut provoquer des blocages système.

L'OS hôte lui-même a également besoin de marge au-delà de ce que les conteneurs utilisent. Le cache de pages Linux, les tampons noyau et les démons système se disputent tous la RAM. En règle générale, ne planifiez jamais une pile qui laisse moins de 10 à 15 % de la RAM totale libre pour l'hôte après avoir additionné les limites des conteneurs. Sur un appareil de 4 GB, cela signifie garder au moins 400 à 600 MB non alloués.

Conseils pour optimiser la RAM

Utilisez des images de base minimales (alpine, distroless) pour réduire l'empreinte. Définissez des limites mémoire explicites (--memory) pour éviter qu'un conteneur ne consomme toute la RAM. Surveillez l'utilisation réelle avec docker stats ou Prometheus. Pour les applications JVM, configurez -Xmx en fonction de la limite du conteneur.

Erreurs courantes lors du dimensionnement de la RAM Docker

  • Ne définir aucune limite : sans limite --memory, n'importe quel conteneur peut consommer toute la RAM de l'hôte, faisant tomber tous les autres services de la machine.
  • Confondre réservation et limite : définir une mem_reservation élevée ne plafonne pas l'utilisation — un conteneur avec une grande réservation et sans limite peut toujours épuiser la RAM de l'hôte.
  • Ignorer la surcharge de l'OS hôte : allouer 100 % de la RAM physique aux conteneurs ne laisse rien pour le noyau, le moteur Docker et les processus d'arrière-plan.
  • Dimensionner à partir de la documentation des images plutôt que de l'utilisation réelle : les images officielles indiquent souvent des exigences minimales. Le RSS réel sous votre charge de travail réelle peut être 2 à 5 fois plus élevé. Vérifiez toujours avec docker stats.
  • Oublier les paramètres de tas du runtime : les conteneurs pour applications JVM ou Node sans plafond de tas défini tenteront d'utiliser autant de mémoire que la limite du conteneur le permet — ou la dépasseront et déclencheront un kill OOM.

Questions fréquentes

Que se passe-t-il quand un conteneur dépasse sa limite ?

Le kernel Linux tue le processus avec un OOMKilled. Docker affiche alors un exit code 137. Pour éviter cela, augmentez la limite ou optimisez votre application. Configurez aussi des restart policies pour relancer automatiquement le conteneur.

Faut-il aussi limiter le CPU ?

Oui, idéalement. Sans limites CPU, un conteneur peut monopoliser les cœurs et ralentir les autres. Utilisez --cpus=1.5 pour limiter à 1,5 cœur, ou --cpu-shares pour des priorités relatives.

Dois-je configurer le swap pour les conteneurs Docker ?

Docker vous permet de définir une limite de swap séparément avec --memory-swap. Si vous définissez --memory=512m et --memory-swap=1g, le conteneur obtient 512 MB de RAM plus 512 MB de swap. Le swap constitue un filet de sécurité qui empêche les kills OOM immédiats, mais compter sur le swap pour un fonctionnement normal dégrade significativement les performances — surtout sur le stockage flash. Utilisez le swap comme tampon de dernier recours, pas comme substitut à une RAM suffisante. Sur les systèmes sans flag --memory-swap explicite, Docker applique par défaut le double de la limite mémoire en swap.

Comment savoir combien de RAM mes conteneurs en cours d'exécution utilisent réellement ?

Exécutez docker stats pour voir en temps réel le CPU, l'utilisation mémoire et les limites mémoire de chaque conteneur en cours d'exécution. La colonne MEM USAGE affiche le RSS (resident set size) actuel du conteneur. Comparez-le à vos limites configurées pour voir la marge disponible pour chaque conteneur. Pour un instantané ponctuel, utilisez docker stats --no-stream. Vous pouvez également inspecter un conteneur spécifique avec docker inspect <name> et rechercher le champ MemoryStats.