Linux OOMKilledВысокая

Docker OOMKilled: причины и способы решения ошибки нехватки памяти

Ошибка OOMKilled в Docker возникает, когда контейнеру не хватает оперативной памяти. Статья объясняет причины и предоставляет проверенные способы решения: от настройки лимитов памяти до оптимизации приложения.

Обновлено 16 февраля 2026 г.
10-15 мин
Средняя
FixPedia Team
Применимо к:Docker Engine 20.10+Docker Compose 1.29+Ubuntu 20.04/22.04CentOS 8/RHEL 8

Что означает ошибка OOMKilled

Ошибка OOMKilled (Out Of Memory Killed) возникает, когда ядро Linux принудительно завершает процесс в контейнере Docker из-за нехватки оперативной памяти (RAM). Это срабатывание механизма OOM killer (Out-Of-Memory killer).

Контейнер завершается с кодом выхода 137 (128 + 9, где 9 — сигнал SIGKILL). В логах Docker вы увидите:

$ docker ps -a
CONTAINER ID   IMAGE          COMMAND                  CREATED        STATUS                     PORTS     NAMES
a1b2c3d4e5f6   my-app:latest  "python app.py"          2 hours ago    Exited (137) 5 minutes ago            my-app

$ docker logs my-app
... (логи приложения) ...
Killed

Ошибка характерна для:

  • Контейнеров с высоким потреблением памяти (базы данных, обработка данных, Java-приложения).
  • Систем с ограниченной RAM (например, облачные инстансы малого размера).
  • Сценариев, где несколько контейнеров конкурируют за память.

Причины возникновения

  1. Недостаточный объём RAM на хосте. Суммарное потребление памяти всеми контейнерами и системами превышает доступную физическую память.
  2. Отсутствие лимитов памяти у контейнера. Если не задать --memory, контейнер может использовать всю свободную RAM хоста, что приведёт к OOM.
  3. Утечки памяти в приложении. Программа внутри контейнера постепенно потребляет всё больше памяти (например, из-за неосвобождения ресурсов).
  4. Неправильно настроенный swap. На хосте может быть недостаточно или отсутствовать swap-пространство, что ускоряет исчерпание RAM.
  5. Агрессивные настройки OOM killer. Ядро может убивать контейнеры с высоким oom_score (по умолчанию у контейнеров он выше, чем у системных процессов).
  6. Запуск контейнера без ограничений на memory-swap. Если задан только --memory, но не --memory-swap, контейнер может использовать swap, что иногда маскирует проблему, но приводит к деградации производительности.

Способ 1: Настройка лимитов памяти при запуске контейнера

Самый прямой способ — явно задать лимиты памяти для контейнера. Это предотвратит исчерпание памяти хоста и гарантирует, что контейнер не будет убит, пока не достигнет своего лимита.

Для docker run:

docker run -d \
  --name my-app \
  --memory=512m \          # жёсткий лимит RAM
  --memory-swap=1g \       # общий лимит (RAM + swap). Если не задать, то по умолчанию равно --memory.
  --memory-reservation=256m \ # мягкий лимит, который Docker пытается соблюдать
  my-image:latest

Для docker-compose.yml:

version: '3.8'
services:
  app:
    image: my-image:latest
    deploy:
      resources:
        limits:
          memory: 512M
          memory-swap: 1G
        reservations:
          memory: 256M

💡 Совет: Начинайте с лимита, немного превышающего нормальное потребление приложения (можно узнать через docker stats). Не устанавливайте лимит равным всей RAM хоста — оставьте память для системы и других процессов.

Способ 2: Оптимизация приложения в контейнере

Если лимиты уже настроены, но контейнер всё равно получает OOM, нужно уменьшать потребление памяти самим приложением.

Для Java-приложений:

Настройте параметры JVM в Dockerfile или команде запуска:

ENV JAVA_OPTS="-Xmx256m -Xms128m"
CMD java $JAVA_OPTS -jar app.jar

Или в docker-compose.yml:

environment:
  - JAVA_OPTS=-Xmx256m

Для Python/Node.js:

  • Используйте стриминговую обработку больших файлов вместо загрузки в память.
  • Уменьшите размер кэшей (например, в Django CACHES['default']['OPTIONS']['MAX_ENTRIES']).
  • Обновите библиотеки — иногда утечки памяти исправляются в новых версиях.

Для веб-серверов (Nginx/Apache):

  • Уменьшите worker_processes и worker_connections.
  • Настройте буферизацию.

Способ 3: Настройка OOM score adjustment

Вы можете влиять на приоритет контейнера при выборе жертвы OOM killer. Параметр --oom-score-adj (от -1000 до 1000) задаёт "вес" контейнера. Чем ниже значение, тем меньше шансов, что контейнер будет убит.

docker run -d \
  --name critical-app \
  --oom-score-adj=-500 \
  my-critical-image

Как выбрать значение:

  • -1000 — максимальная защита (контейнер будет убит в последнюю очередь, но не гарантировано).
  • 0 — значение по умолчанию.
  • 1000 — максимальный приоритет на убийство (не рекомендуется).

⚠️ Важно: Это не отменяет OOM killer, а лишь меняет порядок. Если память закончится, какой-то процесс всё равно будет убит.

Способ 4: Увеличение памяти хоста или настройка swap

Если проблема в нехватке ресурсов на уровне хоста:

  1. Увеличьте RAM на виртуальной машине/сервере (например, в AWS измените тип инстанса).
  2. Добавьте swap-пространство, если его нет или оно мало:
# Проверьте текущий swap
swapon --show

# Создайте swap-файл 2 ГБ
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# Чтобы swap включался автоматически, добавьте в /etc/fstab:
# /swapfile none swap sw 0 0

⚠️ Внимание: Swap на SSD может ускорить износ диска. Используйте только если нет возможности добавить RAM.

Способ 5: Мониторинг и автоматическое реагирование

Настройте мониторинг памяти и автоматические действия:

  • Используйте docker events для отслеживания событий OOM:
    docker events --filter 'event=die' --filter 'status=OOMKilled'
    
  • Интегрируйте с системами мониторинга (Prometheus + cAdvisor, Datadog). Настройте алерты при достижении 80-90% памяти.
  • Используйте оркестраторы (Kubernetes, Docker Swarm), которые могут автоматически перезапускать контейнеры и масштабироваться при нехватке ресурсов.

Профилактика

  1. Всегда задавайте лимиты памяти для продакшн-контейнеров. Используйте --memory и --memory-swap.
  2. Регулярно анализируйте потребление памяти через docker stats или мониторинг.
  3. Тестируйте приложение под нагрузкой с ограниченной памятью (например, через stress-ng внутри контейнера).
  4. Настройте health checks в Docker Compose/Kubernetes, чтобы быстро обнаруживать падение из-за OOM.
  5. Избегайте запуска нескольких memory-intensive контейнеров на одном хосте без должного контроля.
  6. Обновляйте ядро и Docker — новые версии улучшают управление памятью и OOM killer.

FAQ

Можно ли полностью отключить OOM killer для контейнера?
Нет, OOM killer — это механизм ядра Linux. Вы можете только уменьшить oom_score контейнера или увеличить лимиты памяти, чтобы избежать срабатывания.

Почему контейнер с лимитом памяти всё равно получает OOMKilled?
Если лимит задан, контейнер должен быть остановлен Docker до достижения лимита (с кодом 137). Но если лимит не задан, контейнер может использовать всю RAM хоста, и тогда OOM killer ядра его убьёт. Проверьте, что лимит установлен корректно.

Как диагностировать, какое приложение в контейнере потребляет много памяти?
Войдите в контейнер (docker exec -it <container> bash) и используйте утилиты: top, htop, ps aux --sort=-%mem. Для Java-приложений используйте jcmd <pid> VM.native_memory summary.

Что делать, если приложение не может работать в заданных лимитах памяти?
Оптимизируйте код, увеличьте лимит (если есть запас на хосте) или пересмотрите архитектуру: разделите монолит на микросервисы, вынесите тяжёлые операции в отдельные контейнеры с большими лимитами.

Правильно ли задавать --memory-swap в 2x от --memory?
Не всегда. Если приложение не использует swap (например, базы данных), то задание --memory-swap может привести к неожиданному использованию swap и падению производительности. Для таких приложений лучше отключить swap (--memory-swap=-1) или оставить равным --memory.

Часто задаваемые вопросы

Что означает ошибка OOMKilled в Docker?
Как проверить, что контейнер убит из-за OOM?
Можно ли отключить OOM killer для контейнера?
Чем OOMKilled отличается от ошибки 137?

Полезное

Определите потребление памяти контейнера
Настройте лимит памяти для контейнера
Оптимизируйте приложение в контейнере
Настройте OOM score adjustment

Эта статья помогла вам решить проблему?