Ollama в Docker: пять причин проблем с памятью
АйТи Фреш
ИИ и нейросети

Как найти и устранить нехватку памяти у Ollama в контейнере

Автор: , директор ООО «АйТи-Фреш» · · ~12 мин чтения
Измерительные ёмкости показывают, как лимиты и параллельная нагрузка влияют на память контейнера
Память требует точных измерений

Если контейнер Ollama завершает работу или сервер начинает тормозить, сначала проверьте фактическое потребление памяти, лимиты Docker и число одновременных генераций. Универсального объёма RAM для любой модели нет: требования зависят от модели, контекста, параллелизма и того, какие слои размещены на GPU.

Ошибка 1 — лимит Docker не соответствует нагрузке

Не начинайте с произвольного числа в compose-файле. Сначала выясните, сколько памяти доступно самому хосту и сколько реально потребляет контейнер при загрузке выбранной модели и обычном рабочем запросе. Учитывайте не только размер файла модели: на потребление влияют контекст, промежуточные вычисления, число параллельных генераций, процессы операционной системы и другие контейнеры. Поэтому фраза «этой модели всегда нужно восемь гигабайт» не является техническим расчётом. Даже маленькая модель на загруженном сервере может упереться в остаток памяти, а более крупная конфигурация на подходящем хосте — работать штатно. Железо не читает рекламные таблицы.

Проверьте docker stats во время загрузки и генерации, а затем сопоставьте показания с лимитами контейнера и журналом Docker. Compose поддерживает настройку ограничений памяти, но конкретный синтаксис и его действие следует проверять для используемой версии Compose и режима запуска. Например, в Compose Specification можно задать deploy.resources.limits.memory; не копируйте значение из чужого примера, пока не измерили пик потребления. Если лимит слишком низкий, ядро может завершить процесс контейнера при нехватке памяти. Если лимита нет, контейнер способен конкурировать за ресурсы с остальной системой. Ни один из этих вариантов не заменяет замер и запас для хоста.

Я проверяю нагрузку в несколько этапов: запуск сервиса без генерации, загрузка модели, короткий запрос и рабочий сценарий с ожидаемой длиной контекста. На каждом этапе записываю потребление контейнера и хоста. Важен не только максимальный показатель в одном тесте: повторите измерение с тем числом одновременных запросов, которое действительно ожидается. Затем задайте лимит с запасом, оставив хосту память для ОС и соседних служб. Если сервис уходит в OOM, ищите подтверждение в docker inspect, событиях контейнера и системных журналах; слово «завис» само по себе диагноза не даёт.

Не удаляйте ограничение памяти просто потому, что процесс однажды упёрся в него. Так вы можете перенести сбой с контейнера на весь сервер. И не считайте перезапуск лечением: он освобождает занятые процессом ресурсы на время, но не устраняет слишком маленький лимит, чрезмерную нагрузку или неверно выбранный размер контекста. Сначала зафиксируйте метрики, затем меняйте одну настройку и повторяйте тот же сценарий. Так понятно, какое изменение помогло. Если одновременно поменять модель, лимит, контекст и драйвер, результат будет похож на гадание, только с более дорогим счетом за простой.

Лимит выбирают после замера пикового потребления.
Порядок измерения нагрузки, лимита контейнера и запаса хоста
Измерьте нагрузку до настройки

Ошибка 2 — неверные ожидания от swap и cgroup

Swap не является обязательным условием запуска Ollama и не превращается в дополнительную быструю RAM. Это область на диске, куда система при определённых условиях может перемещать страницы памяти; активный обмен с диском способен резко снизить отзывчивость. Наличие и размер swap выбирают для всей машины с учётом нагрузки и политики эксплуатации. Не задавайте «плюс четыре гигабайта» по универсальному рецепту: подходящее значение зависит от устройства, диска, приложений и допустимой деградации. Если swap отсутствует, это само по себе не доказывает причину сбоя. Если он есть, это тоже не гарантия, что контейнер не будет завершён.

У Docker флаг --memory-swap задаёт общий предел памяти вместе с swap, а не объём swap сверх лимита RAM. Например, при --memory=12g и --memory-swap=16g разница между пределами составляет четыре гигабайта для swap, если хост и конфигурация поддерживают соответствующий учёт. Равные значения памяти и memory-swap запрещают контейнеру использовать swap; если задать только --memory, Docker по умолчанию может разрешить общий объём памяти и swap до удвоенного лимита при наличии swap на хосте. Это поведение нужно сверить с официальной документацией и docker info, а не пересказывать как обещание «спасения от падения».

Уточните, какой режим cgroup применяет Docker, и есть ли поддержка нужных контроллеров на хосте. Режим cgroup v2 не требует добавлять --cpu-rt-runtime: этот параметр относится к real-time планировщику и к обычному запуску Ollama отношения не имеет. Проверяйте эффективные ограничения в конфигурации контейнера и метриках хоста; внутри контейнера некоторые системные утилиты показывают состояние всей машины, а не доступный контейнеру остаток. Документация Docker отдельно описывает различия cgroup v1 и v2 и предупреждения о неподдерживаемом учёте swap. Если движок сообщает, что ограничение не поддерживается, запись в Compose может не дать ожидаемого эффекта.

Для диагностики запишите вывод docker info, docker inspect <контейнер> и swapon --show, а затем сопоставьте его с журналом ядра и контейнера. Не меняйте параметры загрузчика и не отключайте OOM-killer ради эксперимента на рабочем узле: такие действия могут ухудшить последствия нехватки памяти. При необходимости сначала проверьте новый профиль на тестовом хосте. Swap может смягчить отдельные пики, если он предусмотрен администратором, однако постоянная нагрузка, превышающая физическую память, требует уменьшить потребление или добавить ресурсы. Диск не выдаёт себя за RAM бесконечно и бесплатно.

Swap замедляет работу и не заменяет расчёт памяти.

Ошибка 3 — слишком много одновременной работы

У Ollama есть очередь и настройки параллельной обработки, а расход ресурсов зависит от количества одновременно выполняемых запросов и их контекста. Поэтому для диагностики важны не легендарные «200 соединений» и не произвольный предел в пятьдесят, а фактический профиль нагрузки. Сверьте число активных генераций, задержки, очередь и потребление памяти. Если нагрузка приходит через несколько приложений, ограничьте параллелизм на уровне вызывающей системы или прокси и проверьте поведение под ожидаемой нагрузкой. Один запрос на короткий текст и несколько длинных генераций — это разные сценарии.

База отмечает параметр OLLAMA_NUM_PARALLEL; официальная справка Ollama уточняет, что он задаёт параллелизм одной модели, по умолчанию равен 1, а потребность в RAM растёт вместе с параллелизмом и контекстом. Значение меняйте после проверки нагрузки и доступной памяти, сверяя поведение с документацией установленной версии. OLLAMA_MAX_CONNS не подтверждена официальной документацией, поэтому не добавляйте её в Compose как будто это поддерживаемый ключ. То же относится к совету применить к Ollama случайную переменную из статьи об ином продукте: неизвестный параметр обычно просто не решает проблему. Нагрузка не становится управляемой от того, что переменная выглядит убедительно.

Если перед API стоит Nginx, limit_conn_zone размещают в контексте http, а limit_conn — в подходящем server или location. Эти директивы ограничивают количество учитываемых одновременных соединений по ключу; они не задают скорость запросов в минуту и не измеряют объём работы модели. Для ограничения частоты запросов у Nginx есть отдельный модуль limit_req. Выбор механизма зависит от цели: ограничить одновременную работу, сгладить частые обращения или защитить API аутентификацией и квотами. Пример из исходной статьи ошибочно помещал объявление зоны внутрь location, так конфиг невалиден.

Сначала составьте профиль: сколько клиентов могут обращаться одновременно, какие запросы самые тяжёлые, сколько времени они занимают и что должно происходить при перегрузке. Затем установите небольшой начальный параллелизм и проверьте, не растут ли очередь и память до опасного уровня. Возвращайте отказ или ставьте запросы в очередь с понятным таймаутом, вместо того чтобы позволять всем приложениям без ограничений занимать ресурсы. Держите API доступным только тем сетям и пользователям, которым он нужен: порт 11434 часто используется локальным API Ollama, но публикация порта на внешний интерфейс сама по себе не является безопасной настройкой.

Лимитируйте параллельную работу по измерениям.
Если по метрикам причина не очевидна, мы поможем проверить Docker-конфигурацию и нагрузку Ollama. Обсудить задачу
Схема показывает отличие ограничения одновременных соединений от частоты запросов
Соединения и частота — разные лимиты

Ошибка 4 — кэш и контекст приняли за утечку

Оставленная в памяти модель и растущий рабочий контекст не означают автоматически утечку. Ollama может удерживать загруженные модели для повторного использования, а объём памяти зависит от размера контекста и числа параллельных запросов. Проверьте список запущенных моделей командой ollama ps, сравните время последнего запроса, настройки времени удержания и метрики процесса. Для API в документации описаны параметры управления временем жизни модели; используйте их только после сверки с версией. Не выдумывайте флаг --no-cache: как универсальная команда запуска Ollama он не подтверждён.

Контекст — это рабочие данные генерации, а не мусор, который обязан бесконечно накапливаться между всеми разговорами. Память может быть выше при длинном контексте, нескольких параллельных запросах или при наличии нескольких загруженных моделей. Уменьшите контекст до реально нужного приложению значения и проверьте число параллельных генераций. Затем повторите одинаковый запрос после завершения предыдущей работы и сравните память. Если потребление остаётся повышенным, определите, какая модель всё ещё загружена; не называйте любой кэш утечкой до анализа графика и журнала.

Для остановки конкретной модели используйте ollama stop <имя-модели>; команда подтверждена базой знаний и справкой Ollama. Ollama API по умолчанию доступен локально на порту 11434, согласно базе и документации; это не то же самое, что остановить контейнер или системную службу. ollama stop all не является подтверждённой командой, а systemctl --user restart ollama подходит лишь для соответствующей нативной пользовательской службы и не перезапускает контейнер. В Docker действия выполняют средствами Docker или Compose, выбрав нужный сервис. Не отправляйте вслепую команды из инструкции для нативной установки внутрь контейнерного сценария: они обращаются к другому способу управления процессом.

Чтобы говорить об утечке, наблюдайте за тем же процессом при сопоставимой нагрузке и убедитесь, что контекст, число моделей и запросов не менялись. Снимайте метрики контейнера и хоста продолжительное время, фиксируйте рестарты и версии образа. Если после остановки модели память процесса освобождается не так, как ожидалось, проверьте фактические метрики cgroup и память процесса: часть памяти может быть занята кэшем ОС, который учитывается иначе. Мониторинг полезен, когда он отвечает на вопрос «что растёт и при какой нагрузке», а не просто рисует красивую линию. Перезапуск — временная мера, не заключение о причине.

Удержание модели не доказывает утечку.
Три возможные причины занятой памяти: загруженная модель, контекст и потенциальная утечка
Рост памяти — ещё не утечка

Ошибка 5 — неверно поняли размещение на GPU и CPU

Проверьте, видит ли контейнер требуемое устройство, и что сообщает Ollama о размещении модели. На машине с NVIDIA проверьте состояние драйвера на хосте и доступность GPU из контейнера; конкретный способ передачи устройства зависит от Docker, настроек runtime и установленного NVIDIA Container Toolkit. Флаг --gpus all — вариант запуска Docker при соответствующей конфигурации, а не универсальное исправление для любой Compose-сборки, любого GPU и любой операционной системы. Если приложение не видит GPU, сначала разберите логи запуска и конфигурацию устройств. Не объявляйте автоматически, что причина именно в нехватке CPU RAM.

Модель может использовать видеопамять, системную память или обе области; итог зависит от аппаратуры, драйвера, модели и её конфигурации. Когда GPU не доступен или его памяти недостаточно, производительность и распределение нагрузки могут отличаться от ожидаемых. Это не доказывает, что Docker-контейнер повреждён. Проверьте, что именно показывает ollama ps, журналы Ollama и утилиты мониторинга GPU на хосте. Сверьте фактическую модель и объём доступной видеопамяти с требованиями выбранного файла. Не опирайтесь на старое универсальное требование к Compute Capability: совместимость зависит от текущего оборудования и поддержки программного стека.

Не меняйте сразу лимиты памяти, GPU runtime и параметры CPU. Зафиксируйте исходное состояние, проверьте модель без параллельной нагрузки и сравните CPU, RAM и VRAM при одном запросе. После этого повторите сценарий с ожидаемым числом запросов. Так становится видно, где упирается конкретный узел. Если GPU не используется, но CPU справляется, это может быть вопрос скорости, а не причина OOM; если память хоста исчерпывается, ищите нагрузку и лимиты. Наблюдайте за журналами при запуске модели: сообщения о неподдерживаемом устройстве дают больше пользы, чем предположение, что дорогая карта «обязана» работать.

План исправления должен соответствовать измерениям: восстановить доступ к GPU, если он действительно нужен; уменьшить контекст или параллелизм, если растут пиковые расходы; изменить лимит, если контейнеру выделено меньше измеренной потребности и хост располагает ресурсом. Затем проверьте длительный рабочий сценарий и холодный перезапуск. Не обещайте, что настройка гарантирует отсутствие любых зависаний: она устраняет конкретно проверенную причину в конкретной конфигурации. Если после изменений данные не сходятся, соберите версии Docker, Ollama, драйвера, конфигурацию контейнера и журналы. Вот уже материал для диагностики, а не ещё один круг магии.

Проверяйте фактическое размещение модели.

Частые вопросы

Сколько RAM нужно для Ollama в Docker?

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

Нужно ли обязательно включать swap?

Нет. Swap настраивают с учётом хоста и допустимого замедления; он не заменяет физическую память и не гарантирует, что процесс не будет завершён.

Есть ли переменная OLLAMA_MAX_CONNS?

Нет: база и официальная документация указывают на OLLAMA_NUM_PARALLEL для параллельной обработки. Не используйте OLLAMA_MAX_CONNS без документации именно для вашей версии.

Как проверить, какие модели загружены?

Выполните `ollama ps`. Для остановки конкретной модели используйте `ollama stop <имя-модели>`.

Как ограничить параллельные запросы?

Настройте параллелизм и очередь в приложении, сверив доступные параметры Ollama с документацией установленной версии. Nginx limit_conn ограничивает одновременные соединения по ключу, а limit_req регулирует частоту запросов.

Столкнулись с похожей задачей? Обращайтесь — решим

Если у вас происходит что-то из описанного в этой статье — или любая другая проблема с ИТ-инфраструктурой, — обращайтесь в любое время. Мои специалисты и я лично разберём ситуацию, найдём настоящую причину и доведём до решения.

Возьмёмся и за разовую задачу, и за постоянное обслуживание. Первичная консультация — бесплатно и без обязательств.

📞 +7 903 729-62-41 ✈ Telegram @ITfresh_Boss

С уважением, Семёнов Евгений Сергеевич, директор «АйТи Фреш» — IT-аутсорсинг для компаний до 50 рабочих мест, 15+ лет практики

Источники

© ООО «АйТи-Фреш» · Москва · Все статьи