Docker pour les devs - 26 - Limiter les ressources de tes conteneurs

Memory limits, CPU limits, OOM killer et monitoring : tout ce qu'il faut savoir pour que tes conteneurs ne mangent pas ton serveur.

  1. 01 Docker pour les devs - 00 - Pourquoi Docker change tout
  2. 02 Docker pour les devs - 01 - Containers vs VMs
  3. 03 Docker pour les devs - 02 - L'architecture de Docker
  4. 04 Docker pour les devs - 03 - Docker Desktop, Engine et alternatives
  5. 05 Docker pour les devs - 04 - Écrire un Dockerfile
  6. 06 Docker pour les devs - 05 - Layers et cache
  7. 07 Docker pour les devs - 06 - Le .dockerignore
  8. 08 Docker pour les devs - 07 - Multi-stage builds
  9. 09 Docker pour les devs - 08 - Choisir son image de base
  10. 10 Docker pour les devs - 09 - Docker Compose, les bases
  11. 11 Docker pour les devs - 10 - Docker Compose avance
  12. 12 Docker pour les devs - 11 - Networking Docker, les bases
  13. 13 Docker pour les devs - 12 - Networking Docker avance
  14. 14 Docker pour les devs - 13 - Volumes et persistance
  15. 15 Docker pour les devs - 14 - Variables d'environnement et secrets
  16. 16 Docker pour les devs - 15 - Permissions et utilisateurs
  17. 17 Docker pour les devs - 16 - Docker et monorepo
  18. 18 Docker pour les devs - 17 - Dev vs Prod
  19. 19 Docker pour les devs - 18 - ENTRYPOINT, CMD et scripts d'initialisation
  20. 20 Docker pour les devs - 19 - Debugger ses conteneurs
  21. 21 Docker pour les devs - 20 - Bases de donnees dans Docker
  22. 22 Docker pour les devs - 21 - Sauvegardes et restauration
  23. 23 Docker pour les devs - 22 - Conteneuriser un frontend
  24. 24 Docker pour les devs - 23 - Sécurité des conteneurs
  25. 25 Docker pour les devs - 24 - Optimisation des images
  26. 26 Docker pour les devs - 25 - Builds multi-platform
  27. 27 Docker pour les devs - 26 - Limiter les ressources de tes conteneurs
  28. 28 Docker pour les devs - 27 - Gerer les logs comme un adulte
  29. 29 Docker pour les devs - 28 - Healthchecks et restart policies
  30. 30 Docker pour les devs - 29 - Nettoyer Docker avant qu'il mange ton disque
  31. 31 Docker pour les devs - 30 - Registries et stratégie de tags
  32. 32 Docker pour les devs - 31 - Docker en CI/CD
  33. 33 Docker pour les devs - 32 - Au-dela de Compose
  34. 34 Docker pour les devs - 33 - Glossaire Docker de A a Z

26 - Limiter les ressources de tes conteneurs

Ce que tu vas apprendre

  • Comment limiter la mémoire et le CPU d'un conteneur
  • Pourquoi le OOM killer tue tes conteneurs sans prevenir
  • Comment surveiller la consommation avec docker stats
  • Les options swap et ulimits
  • Des guidelines concrets pour dimensionner en prod

Prerequisites

  • Savoir lancer un conteneur Docker
  • Connaitre Docker Compose pour les exemples en YAML

Un vendredi soir, mon conteneur Node.js a décidé de manger 8 Go de RAM sur un serveur qui en avait 8. Le kernel Linux a fait ce qu'il sait faire : il a tue le processus le plus gourmand. Mon API a disparu sans laisser de trace dans les logs. Pas d'erreur, pas de warning. Juste un conteneur marque "Exited (137)".

Ce jour-la j'ai appris qu'un conteneur sans limites de ressources, c'est une bombe a retardement.

Par défaut, aucune limite

Quand tu lances un conteneur Docker sans options, il peut utiliser toute la RAM et tous les CPU de la machine hote. Docker ne pose aucune restriction. Ton conteneur a acces a tout, exactement comme un processus natif.

Ca marche sur ton poste de dev. Ca explose en production quand trois conteneurs se battent pour les memes ressources.

Limiter la mémoire

La méthode directe avec docker run :

bashdocker run --memory=512m --memory-swap=1g mon-app

--memory=512m definit la limite de RAM. --memory-swap=1g definit la limite combinee RAM + swap. Si tu veux désactiver le swap, passe --memory-swap a la meme valeur que --memory.

En Compose, ca se configure dans deploy.resources :

yamlservices:
  api:
    image: mon-app:latest
    deploy:
      resources:
        limits:
          memory: 512M
        reservations:
          memory: 256M

limits est le plafond dur. reservations est ce que Docker garantit a ton conteneur. La reservation sert au scheduler pour décider ou placer les conteneurs. La limite sert au kernel pour tuer ceux qui depassent.

Le OOM killer, ton ennemi invisible

OOM signifie Out Of Memory. Quand un conteneur dépassé sa limite mémoire, le kernel Linux invoque le OOM killer. Il tue le processus principal du conteneur. Exit code 137.

Le problème : le OOM killer ne previent pas. Pas de log dans ton application, pas de signal propre. Le processus disparaît.

Pour vérifier si un conteneur a ete tue par le OOM killer :

bashdocker inspect mon-conteneur --format='{{.State.OOMKilled}}'

Si ca renvoie true, tu sais ce qui s'est passe.

Pour éviter ca, tu as deux options : augmenter la limite, ou corriger la fuite mémoire. Dans la vraie vie, c'est souvent un mix des deux.

Limiter le CPU

Docker permet de limiter le CPU de plusieurs facons :

bashdocker run --cpus=1.5 mon-app

Ca donne acces a 1.5 coeurs. Pas plus. Si ta machine a 4 coeurs, le conteneur en utilise au maximum 1.5.

bashdocker run --cpu-shares=512 mon-app

Les shares sont relatives. La valeur par défaut est 1024. Un conteneur a 512 shares recevra la moitie du CPU par rapport a un conteneur a 1024. Mais seulement quand il y a competition. Si la machine est tranquille, le conteneur peut utiliser plus.

En Compose :

yamlservices:
  api:
    image: mon-app:latest
    deploy:
      resources:
        limits:
          cpus: "1.5"
        reservations:
          cpus: "0.5"

Mon conseil : cpus pour une limite dure, cpu-shares pour une repartition equitable sans plafond strict.

Surveiller avec docker stats

bashdocker stats

Cette commande affiche en temps réel la consommation de chaque conteneur :

CONTAINER   CPU %   MEM USAGE / LIMIT   MEM %   NET I/O     BLOCK I/O
api         2.34%   187MiB / 512MiB     36.52%  1.2kB/540B  0B/0B
db          0.89%   312MiB / 1GiB       30.47%  540B/1.2kB  8.2MB/4.1MB

Pour un snapshot sans flux continu :

bashdocker stats --no-stream

C'est la première chose que je regarde quand un serveur ralentit. Avant meme les logs. Sur paltemps.fr, j'ai un cron qui enregistre la sortie de docker stats toutes les 5 minutes dans un fichier. Rustique mais efficace.

Swap et ulimits

Par défaut, Docker autorise le swap. Un conteneur qui dépassé sa limite mémoire peut deborder sur le disque. C'est mieux qu'un crash, mais les performances s'effondrent.

Pour désactiver le swap :

bashdocker run --memory=512m --memory-swap=512m mon-app

Quand --memory et --memory-swap sont egaux, pas de swap.

Les ulimits controlent les limites système du conteneur :

yamlservices:
  api:
    image: mon-app:latest
    ulimits:
      nofile:
        soft: 65536
        hard: 65536
      nproc:
        soft: 4096
        hard: 4096

nofile contrôle le nombre de fichiers ouverts. Essentiel pour les serveurs qui gerent beaucoup de connexions. nproc contrôle le nombre de processus. Une protection contre les fork bombs.

Guidelines de dimensionnement

Apres avoir déployé pas mal de conteneurs en production, voici mes regles :

  • API Node.js/Express : 256-512 Mo de RAM, 0.5-1 CPU
  • Application Java/Spring : 512 Mo-1 Go de RAM, 1-2 CPU
  • PostgreSQL : 512 Mo-2 Go de RAM selon la taille de la base
  • Redis : 128-256 Mo pour du cache, plus si persistence
  • Nginx : 64-128 Mo de RAM, 0.25 CPU

Ces valeurs sont des points de depart. Demarre avec ca, surveille avec docker stats, ajuste. Ne surdimensionne pas par precaution. Un conteneur qui reserve 2 Go mais n'en utilise que 200 Mo, c'est du gaspillage qui empeche d'autres conteneurs de tourner.

La reservation (reservations) devrait correspondre a l'usage normal. La limite (limits) devrait correspondre a un pic raisonnable. Si ton app consomme habituellement 200 Mo et monte a 400 Mo en pic, mets une reservation a 256 Mo et une limite a 512 Mo.

Résumé

  • Par défaut, un conteneur n'a aucune limite de ressources
  • --memory et --cpus posent des limites dures
  • Le OOM killer tue sans prevenir les conteneurs qui depassent leur limite mémoire (exit code 137)
  • docker stats est ton outil de monitoring de base
  • Dimensionne en surveillant l'usage réel, pas en devinant

Precedent : 25 - Multi-platform | Suivant : 27 - Logs

Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.