ИНСТРУКЦИЯ (ПРАКТИЧНАЯ): Ollama на Tesla K80 с нуля
Проверено: Ubuntu 26.04 LTS, 2x Tesla K80, драйвер 470.256.02 (патч joanbm), Docker + nvidia-container-toolkit, контейнер dogkeeper886/ollama37:v2.0.3. Работает, включая автозапуск после перезагрузки.
Зачем это всё (читайте 1 минуту, сэкономит час)
K80 — Kepler (CC 3.7). NVIDIA выпилила его поддержку из драйверов и Ollama. Обход — 3 слоя:
| Слой | Что | Зачем |
|---|---|---|
| 1 | Патченный драйвер 470.256.02 | единственный драйвер для K80, пропатчен под новое ядро |
| 2 | Модуль nvidia_uvm + узел /dev/nvidia-uvm | без него CUDA в контейнере падает: ggml_cuda_init: failed... unknown error, VRAM 0 B. nvidia-smi при этом работает — вот главная ловушка |
| 3 | Контейнер dogkeeper886/ollama37 | исходники Ollama уже пропатчены под sm_37, внутри лежат библиотеки CUDA 11.4 |
Ключевые грабли (проверено на живом стенде):
- НЕ ставить
--gpus allвместе с--runtime=nvidia— GPU молча не пробрасывается. Только--runtime=nvidia. - CUDA toolkit на хосте не нужен для работы контейнера (внутри образа всё своё). Ставить только если планируете сами что-то компилировать.
- Узел /dev/nvidia-uvm не создаётся сам — патченный драйвер не ставит udev-правило, а
nvidia-modprobe -uна нём не работает. Поэтому нужен systemd-сервис (шаг 5.2) — это не костыль, а замена отсутствующего механизма.
ШАГ 1. База (5 минут)
apt update && apt upgrade -y
apt install -y git wget curl build-essential linux-headers-$(uname -r) libglvnd-dev
linux-headersиbuild-essential— для сборки драйвера. Больше ничего не нужно.
ШАГ 2. Драйвер (15-30 минут, компиляция)
git clone https://github.com/joanbm/nvidia-470xx-linux-mainline /opt/nvidia-470xx
cd /opt/nvidia-470xx
./install
Скрипт скачает драйвер с сайта NVIDIA, наложит патчи и соберёт модули под ваше ядро. В конце — обязательно перезагрузиться и проверить:
reboot
nvidia-smi
# Должно быть: 2x Tesla K80 (12206 MiB), Driver Version: 470.256.02
ШАГ 3. Docker + NVIDIA Container Toolkit (10 минут)
# --- Docker (официальный репозиторий) ---
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" > /etc/apt/sources.list.d/docker.list
# --- NVIDIA Container Toolkit (нужен для проброса GPU в Docker) ---
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt update
apt install -y docker-ce docker-ce-cli containerd.io nvidia-container-toolkit
# Подключить runtime nvidia к Docker
nvidia-ctk runtime configure --runtime=docker
systemctl restart docker
ШАГ 4. UVM-фикс (главный; 5 минут)
Без него GPU в контейнере виден как 0 B VRAM. nvidia-smi работает — не обманывайтесь.
4.1. Автозагрузка модуля:
echo 'nvidia-uvm' > /etc/modules-load.d/nvidia-uvm.conf
modprobe nvidia-uvm
lsmod | grep nvidia_uvm # должен появиться
4.2. Сервис создания узла /dev/nvidia-uvm:
cat > /etc/systemd/system/nvidia-uvm-device.service <<'EOF'
[Unit]
Description=Create /dev/nvidia-uvm node with dynamic major
After=systemd-modules-load.service
ConditionPathExists=/proc/driver/nvidia/version
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'major=$(awk "/ nvidia-uvm$/ {print \$1}" /proc/devices); if [ -n "$major" ] && [ ! -e /dev/nvidia-uvm ]; then mknod -m 666 /dev/nvidia-uvm c $major 0; fi'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now nvidia-uvm-device.service
ls -la /dev/nvidia-uvm # узел появился
Почему так: nvidia-uvm регистрирует устройство с динамическим major (на стенде был 509, после перезагрузки стал 234). Узел в /dev не создаётся автоматически — патченный драйвер не содержит udev-правила, а nvidia-modprobe (официальный создатель узлов) на нём не срабатывает. Сервис просто достаёт текущий major из /proc/devices и делает mknod. Один раз — и больше о нём не думаете.
4.3. Перегенерация CDI-спек (важно для правильного major в контейнере):
nvidia-ctk cdi generate --output=/etc/cdi/nvidia.yaml
ШАГ 5. Запуск контейнера (2 минуты)
docker run -d --name ollama37 \
--runtime=nvidia \
-e OLLAMA_HOST=0.0.0.0:11434 \
-p 11434:11434 \
--restart unless-stopped \
-v ollama-data:/root/.ollama \
dogkeeper886/ollama37:v2.0.3
⚠️ Только --runtime=nvidia, без --gpus all. --restart unless-stopped — контейнер сам поднимется после перезагрузки.
ШАГ 6. Проверка (5 минут)
# 1. API живой
curl http://localhost:11434/api/version # {"version":"2.0.3"}
# 2. ГЛАВНЫЙ ПРИЗНАК РАБОТЫ — GPU в логах:
docker logs ollama37 2>&1 | grep "inference compute"
# ✅ library=CUDA ... total="11.9 GiB" (две таких строки)
# ❌ library=cpu — фикс из ШАГА 4 не применился
# 3. Модели и генерация
curl http://localhost:11434/api/pull -d '{"model":"gemma3:4b","stream":false}'
curl http://localhost:11434/api/generate -d '{"model":"gemma3:4b","prompt":"1+1=?","stream":false}'
# 4. GPU реально нагружается во время ответа (в другом терминале):
nvidia-smi --query-gpu=index,memory.used,utilization.gpu --format=csv
# ✅ 4817 MiB, utilization 60-90%
ШАГ 7. Финальный тест — перезагрузка (обязателен!)
reboot
# через 1-2 минуты, по порядку:
lsmod | grep nvidia_uvm # модуль загружен сам
ls -la /dev/nvidia-uvm # узел создан сервисом
docker ps # ollama37 Up (healthy)
docker logs ollama37 2>&1 | grep "inference compute" # library=CUDA
curl http://localhost:11434/api/generate -d '{"model":"tinyllama:1.1b","prompt":"hi","stream":false}'
Всё зелёное — система готова и переживёт любые перезагрузки.
Диагностика
| Симптом | Причина | Решение |
|---|---|---|
ggml_cuda_init: failed... unknown error, VRAM 0 B | нет UVM-модуля или узла | Шаг 4.1 + 4.2 |
library=cpu в логах ollama | UVM-фикс не сделан | Шаг 4 полностью |
| GPU виден вручную, но не в docker run | --gpus all вместе с --runtime=nvidia | убрать --gpus all |
| После перезагрузки сломалось, вручную работало | CDI-спеки со старым major | Шаг 4.3 + перезапуск контейнера |
| UBSAN-варнинги в dmesg (nvidia_uvm) | косметика на ядре 7.0 | игнорировать |
Чеклист
- [ ] nvidia-smi: 2x K80, 470.256.02
- [ ] /dev/nvidia-uvm существует
- [ ] docker logs:
library=CUDA11.9 GiB x2 - [ ] gemma3:4b отвечает, GPU 60-90%
- [ ] после reboot всё работает само
Ваш WebUI-симптом подтверждён тестом: num_predict=300 → дума съедает всё, content пустой. Решение: в OpenWebUI выставить Max Tokens ≥ 4096.