Управление ресурсами контейнеров
TL;DR:
--memory=512m— жёсткий лимит RAM.--cpus=1.0— лимит CPU. Без лимитов один контейнер может убить весь хост через OOM.
По умолчанию контейнер не имеет ограничений и может использовать все доступные ресурсы хоста (все ядра CPU, всю оперативную память). Это опасно: один сбойный процесс может вызвать отказ в обслуживании (DoS) для всего сервера.
В этом руководстве мы настроим жесткие (Hard) и мягкие (Soft) лимиты.
1. Лимиты оперативной памяти (Memory)
Управление памятью критично. Если память на хосте закончится, ядро Linux (OOM Killer) начнет убивать процессы (часто — сам Docker Daemon или базу данных).
Hard Limit (--memory)
Жесткое ограничение. Если контейнер попытается взять больше — он будет убит (Exit Code 137).
# Ограничить потребление до 512 МБ
docker run -d --name my-app \
--memory="512m" \
nginxSoft Limit (--memory-reservation)
Мягкое ограничение. Docker гарантирует контейнеру этот объем, но разрешает взять больше, если на хосте есть свободная память.
# Гарантировать 256МБ, но разрешить расти до 512МБ
docker run -d \
--memory="512m" \
--memory-reservation="256m" \
nginxЕсли на хосте кончится память, Docker в первую очередь будет “ужимать” контейнеры, потребляющие больше своей резервации.
Swap (--memory-swap)
По умолчанию Docker разрешает использовать Swap в объеме 2 * memory.
Чтобы отключить swap для контейнера (для предсказуемой производительности):
# Память 512МБ, Swap 512МБ (то есть swap = memory, доп. свопа нет)
docker run -d --memory="512m" --memory-swap="512m" nginx2. Лимиты процессора (CPU)
CPU Count (--cpus)
Самый простой способ. “Дать контейнеру мощность 1.5 ядер”.
# Ограничить использование до 1.5 ядер (например, 1 ядро на 100% + 1 на 50%)
docker run -d --cpus="1.5" nginxCPU Pinning (--cpuset-cpus)
Привязка контейнера к конкретным физическим ядрам. Полезно для баз данных и High-Load систем, чтобы избежать переключений контекста (Context Switching).
# Использовать только 0-е и 1-е ядро
docker run -d --cpuset-cpus="0,1" nginxCPU Shares (--cpu-shares)
Относительный вес. Работает только когда CPU загружен на 100%. По умолчанию у всех 1024.
- Контейнер А (1024) и Контейнер Б (512).
- Если CPU свободен — оба могут жарить на 100%.
- Если CPU забит — А получит 66% времени, Б — 33%.
3. Обновление ресурсов на лету
Вам не нужно пересоздавать контейнер, чтобы изменить лимиты. Используйте docker update.
# Увеличить память до 1ГБ и CPU до 2 ядер для работающего контейнера
docker update --memory "1g" --cpus "2.0" my-appПримечание: Работает только если cgroups v2 корректно настроены на хосте (стандарт для современных Linux).
4. Java и Garbage Collection
JVM (Java) и Node.js (V8) должны знать о лимитах контейнера, чтобы правильно настроить Heap Size и сборщик мусора.
- В старых версиях Java (8u121 и ниже) JVM видела всю память хоста (64ГБ) и падала с OOM, пытаясь выделить 4ГБ в контейнере с лимитом 512МБ.
- В современных версиях (
-XX:+UseContainerSupportвключен по умолчанию) это работает автомтически.
Best Practice для Java:
Всегда задавайте -XX:MaxRAMPercentage=75.0. Это заставит JVM использовать 75% от лимита контейнера (--memory) под Heap, оставляя 25% на native memory и стек потоков.
# compose.yaml
services:
java-app:
image: openjdk:17
deploy:
resources:
limits:
memory: 1G
environment:
- JAVA_TOOL_OPTIONS="-XX:MaxRAMPercentage=75.0"5. Мониторинг
Быстрый способ проверить нагрузку в консоли:
docker stats- Показывает CPU %, Mem Usage / Limit, Net I/O.
--no-stream— вывести снимок один раз.--format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"— отформатировать вывод.
Типичные ошибки
| Ошибка | Симптом | Решение |
|---|---|---|
Нет --memory на проде | Один контейнер съел всю RAM → OOM Killer убил sshd | Всегда ставить --memory и --cpus |
Java -Xmx больше --memory | Контейнер убит с exit code 137 (OOM) | MaxRAMPercentage=75 автоматически подстраивается под cgroup |
--memory-swap не задан | Контейнер использует swap, «тормозит» вместо падения | --memory-swap=512m (равно —memory) отключает swap |
--cpu-shares вместо --cpus | Лимит не работает когда CPU свободен | --cpu-shares — относительный вес, не жёсткий лимит. Используй --cpus |