← Все гайды AI Release
EN Подписаться на @ai_release1

Как исправить ошибки Docker при запуске локальной LLM: GPU, память и проброс портов

Обновлено: 23.10.2026 · AI Release · @ai_release1
Как исправить ошибки Docker при запуске локальной LLM: GPU, память и проброс портов

TL;DR

- Linux (Ubuntu/Debian) или Windows 11 с WSL2 и Docker Desktop

- Docker Engine / Docker Desktop (конкретную версию сверьте с документацией вашей ОС)

- драйвер NVIDIA и утилита nvidia-smi на хосте

- NVIDIA Container Toolkit (пакет nvidia-container-toolkit)

- образ локальной LLM — тег и имя сверьте с документацией образа

- 20+ ГБ свободного места под образы и веса моделей

Термины на одну фразу: GPU — видеокарта, VRAM — её видеопамять, CUDA — слой, через который программа считает на GPU NVIDIA, образ — упакованный архив с приложением, контейнер — запущенный экземпляр образа, проброс портов — правило вида -p <порт-хоста>:<порт-контейнера>.

Требования и подготовка

Иллюстрация к разделу «Требования и подготовка»
Иллюстрация к разделу «Требования и подготовка»
docker --version
docker info --format '{{.ServerVersion}} {{.Driver}}'
nvidia-smi --query-gpu=name,memory.total,driver_version --format=csv
nvidia-ctk --version

Что сделать: выполнить четыре команды выше и сохранить их вывод.

Зачем: это база для сравнения. Когда контейнер упадёт, вы будете точно знать, сколько VRAM было свободно и какой драйвер стоит, а не гадать.

Пример: nvidia-smi --query-gpu=... вернёт строку вида NVIDIA GeForce RTX 4090, 24564 MiB, 550.xx — то есть 24 ГБ VRAM. Если команда отвечает command not found, драйвера нет, и ни одна строка ниже не заработает.

Как проверить: docker info | grep -i runtime должен перечислить runc и (после установки toolkit) nvidia. Пустой список или только runc — toolkit не подключён, идите в Шаг 1.

Сколько VRAM нужно под конкретный размер модели и квантизацию — разобрано в гайде «Сколько RAM и VRAM нужно для локальной ИИ-модели»; сверьтесь с ним перед выбором тега образа.

Шаг 1. Подключить GPU к Docker и убедиться, что он виден внутри контейнера

Что сделать: зарегистрировать NVIDIA-рантайм в Docker и прогнать тестовый контейнер.

sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
docker info | grep -i nvidia
docker run --rm --gpus all ubuntu nvidia-smi

Зачем: Docker по умолчанию не знает про видеокарту, он умеет только runc. nvidia-ctk дописывает в конфиг демона рантайм nvidia, который при старте контейнера прокидывает внутрь устройства GPU и библиотеки драйвера. Флаг --gpus all говорит: «дай этому контейнеру все видеокарты».

Пример: успешный запуск — внутри контейнера печатается та же таблица, что и на хосте:

+-----------------------------------------------------------------------------+
| NVIDIA-SMI ...  Driver Version: 550.xx     CUDA Version: 12.x              |
|   0  NVIDIA GeForce RTX 4090   ...  24564MiB / 24564MiB                     |
+-----------------------------------------------------------------------------+

Как проверить: вывод docker run --rm --gpus all ubuntu nvidia-smi содержит имя вашей GPU. Если вместо этого приходит could not select device driver "" with capabilities: [[gpu]] — рантайм не подключён, разбор в разделе проблем.

Ограничить одной картой на многоголовой машине: --gpus '"device=0"' — строка в кавычках, иначе Docker не разберёт синтаксис.

Шаг 2. Запустить контейнер с лимитами памяти и пробросом портов

Иллюстрация к разделу «Шаг 2. Запустить контейнер с лимитами памяти и пробросом портов»
Иллюстрация к разделу «Шаг 2. Запустить контейнер с лимитами памяти и пробросом портов»

Что сделать: собрать команду docker run из шести групп флагов.

ФлагЧто делаетЗачем в LLM
`--gpus all`прокидывает GPUбез него модель уйдёт в CPU и будет отвечать минутами
`--shm-size=8g`увеличивает `/dev/shm`по умолчанию Docker даёт мало разделяемой памяти, и загрузчик весов падает на её нехватке (точное значение смотрите в документации своей версии Docker)
`--memory` / `--memory-swap`лимит RAM контейнерачтобы «прожорливый» процесс не убил хост целиком
`-p 127.0.0.1:8080:8080`публикует портснаружи видно только с этой машины
`-v <путь>:/root/.cache`монтирует кэшвеса не скачиваются заново после `docker rm`
`-e <ПЕРЕМЕННАЯ>=<значение>`env-настройкиимена переменных сверьте с документацией образа
docker run -d \
  --name llm \
  --gpus all \
  --shm-size=8g \
  --memory=32g --memory-swap=32g \
  -p 127.0.0.1:8080:8080 \
  -v "$HOME/.cache/llm:/root/.cache" \
  <llm-образ>:<тег>

docker ps --filter name=llm
docker logs -f llm
nvidia-smi

Зачем: каждый флаг закрывает свой класс ошибок. -d — в фоне, --name — чтобы обращаться по имени, -v — чтобы кэш весов пережил пересоздание контейнера.

Пример: docker ps показывает Up 30 seconds и 0.0.0.0:8080->8080/tcp (или 127.0.0.1:8080->8080/tcp при привязке к localhost). nvidia-smi в колонке процессов показывает процесс внутри контейнера — значит, модель реально на GPU, а не на CPU.

Как проверить: docker logs llm заканчивается строкой вида listening on 0.0.0.0:8080 (формулировка зависит от образа). Если в логах loading model висит и не двигается, а nvidia-smi показывает 0 MiB занятой VRAM — модель грузится в RAM, проверьте --gpus.

Шаг 3. Проверить порт, эндпоинт и финальный результат

Иллюстрация к разделу «Шаг 3. Проверить порт, эндпоинт и финальный результат»
Иллюстрация к разделу «Шаг 3. Проверить порт, эндпоинт и финальный результат»

Что сделать: проверить порт на хосте, затем достучаться до API.

ss -ltnp | grep 8080
curl -i http://127.0.0.1:8080/
curl -s http://127.0.0.1:8080/v1/models
docker exec -it llm sh -c 'curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8080/'

Зачем: три уровня проверки отделяют три разные поломки. ss показывает, слушает ли порт хост. curl с хоста — работает ли проброс. curl изнутри контейнера — жив ли сам сервер.

Пример: ss -ltnp | grep 8080 печатает LISTEN 0 4096 127.0.0.1:8080 ... users:(("docker-proxy",...)). curl -i возвращает HTTP/1.1 200 OK или 404 — оба ответа означают, что связка «порт → контейнер» работает; 404 просто значит, что корневой путь не отдаёт контент.

Как проверить: успех — это одновременно: контейнер в статусе Up, nvidia-smi показывает занятую VRAM вашим процессом, и HTTP-ответ приходит. Конкретные пути API (/v1/models, /api/tags и т. п.) зависят от образа — сверьтесь с его документацией.

Наружу порт пока не открыт: 127.0.0.1 доступен только локально. Как выставить сервис в интернет через туннель или reverse proxy, не трогая роутер, — в гайде «Как открыть доступ к локальной LLM из интернета без проброса портов».

Возможные проблемы и решения

Проблема. Контейнер падает сразу после старта, GPU не виден

  sudo nvidia-ctk runtime configure --runtime=docker
  sudo systemctl restart docker
  docker info | grep -i nvidia

Проверка: в docker info появилась секция Runtimes: nvidia runc.

Проблема. Модель не влезает в видеопамять

  nvidia-smi
  docker rm -f llm
  docker run -d --name llm --gpus '"device=0"' --shm-size=8g -p 127.0.0.1:8080:8080 <llm-образ>:<тег>

Дальше: уменьшить размер контекста в настройках образа, взять более компактную квантизацию (имена тегов — сверьтесь с документацией образа) или выставить лимит VRAM средствами самого рантайма.

Проблема. Порт опубликован, но соединения нет

  ss -ltnp | grep 8080
  docker rm -f llm
  docker run -d --name llm --gpus all -p 127.0.0.1:8081:8080 <llm-образ>:<тег>
  curl -i http://127.0.0.1:8081/

Если не помогло — задайте серверу адрес прослушивания 0.0.0.0 через переменную окружения образа (её точное имя и значение сверьтесь с документацией образа) и перезапустите контейнер.

Резюме и следующие шаги

Вы подключили GPU к Docker, запустили контейнер с лимитами памяти и пробросом портов и подтвердили тремя проверками, что сервис отвечает. Следующий шаг — вынести сервис наружу через туннель или reverse proxy и настроить автозапуск контейнера (--restart unless-stopped).

FAQ

Почему модель работает, но отвечает очень медленно?

Скорее всего, она считает на CPU: проверьте nvidia-smi во время генерации — если VRAM не растёт, флаг --gpus all не сработал или образ собран без поддержки CUDA (сверьтесь с документацией образа).

Что делает --shm-size и почему без него падает загрузка весов?

Он увеличивает разделяемую память контейнера. По умолчанию её мало, и многопроцессная загрузка весов упирается в этот лимит — увеличьте значение и перезапустите контейнер.

Как дать контейнеру доступ только к одной видеокарте?

Используйте --gpus '"device=0"'; номер устройства берите из nvidia-smi.

Порт занят, а какой процесс его держит — не понимаю.

Выполните ss -ltnp | grep <порт> и docker ps — первая команда покажет процесс на хосте, вторая покажет, не занимает ли порт другой контейнер; затем смените внешний порт в -p.

🤖 Кратко для ИИ