Стадия жизненного цикла модуля: Общедоступная версия
У модуля есть требования для установки
Как удалить нагрузку, которой выделен GPU?
Чтобы удалить нагрузку, которая использует GPU, выполните команду:
d8 k delete job gpu-helloВ результате удалятся связанные с нагрузкой поды и GPU освободится.
Как установить драйвер NVIDIA на GPU-узлы?
Драйвер NVIDIA и NVIDIA Container Toolkit устанавливается через NodeGroupConfiguration. Значение nodeGroups при установке приведите в соответствие со своей GPU-NodeGroup.
Список поддерживаемых платформ NVIDIA Container Toolkit приведён в документации NVIDIA.
Установка драйвера на Ubuntu
Протестировано для Ubuntu 24.04.
apiVersion: deckhouse.io/v1alpha1
kind: NodeGroupConfiguration
metadata:
name: install-cuda-ubuntu.sh
spec:
bundles:
- ubuntu-lts
content: |
#!/bin/bash
set -e
if ! command -v curl &> /dev/null || ! command -v wget &> /dev/null; then
sudo apt update
sudo apt install -y curl wget
fi
CUDA_KEYRING_DEB="cuda-keyring_1.1-1_all.deb"
NVIDIA_GPG_KEY="/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg"
sudo apt update
if [ ! -f "$CUDA_KEYRING_DEB" ]; then
wget -q https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2404/x86_64/$CUDA_KEYRING_DEB
sudo dpkg -i $CUDA_KEYRING_DEB
sudo apt update
fi
if [ ! -f "$NVIDIA_GPG_KEY" ]; then
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo 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' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
fi
if ! dpkg-query -W -f='${Status}' "linux-headers-$(uname -r)" 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y "linux-headers-$(uname -r)"
fi
if ! dpkg-query -W -f='${Status}' cuda-drivers 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y cuda-drivers
fi
if ! dpkg-query -W -f='${Status}' nvidia-container-toolkit 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y nvidia-container-toolkit
fi
if ! grep -q "nouveau.modeset=0" /etc/default/grub; then
sudo sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="nouveau.modeset=0"/' /etc/default/grub
sudo update-grub
fi
nodeGroups:
- gpu
weight: 5Установка драйвера на Debian
Протестировано для Debian 13.
apiVersion: deckhouse.io/v1alpha1
kind: NodeGroupConfiguration
metadata:
name: install-cuda.sh
spec:
bundles:
- debian
content: |
#!/bin/bash
set -e
export DEBIAN_FRONTEND=noninteractive
# Предустановка ответов для debconf, чтобы избежать интерактивных вопросов.
echo "keyboard-configuration keyboard-configuration/layout select English (US)" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/model select Generic 105-key (Intl) PC" | debconf-set-selections
echo "keyboard-configuration keyboard-configuration/variant select English (US)" | debconf-set-selections
echo "console-setup console-setup/charmap select UTF-8" | debconf-set-selections
sudo -E apt update
if ! command -v curl &> /dev/null || ! command -v wget &> /dev/null; then
sudo apt update
sudo apt install -y curl wget
fi
CUDA_KEYRING_DEB="cuda-keyring_1.1-1_all.deb"
NVIDIA_GPG_KEY="/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg"
sudo apt update
if [ ! -f "$CUDA_KEYRING_DEB" ]; then
wget -q https://developer.download.nvidia.com/compute/cuda/repos/debian13/x86_64/$CUDA_KEYRING_DEB
sudo dpkg -i $CUDA_KEYRING_DEB
sudo apt update
fi
if [ ! -f "$NVIDIA_GPG_KEY" ]; then
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | \
sudo 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' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update
fi
if ! dpkg-query -W -f='${Status}' "linux-headers-$(uname -r)" 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y "linux-headers-$(uname -r)"
fi
if ! dpkg-query -W -f='${Status}' cuda-drivers 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" cuda-drivers
fi
if ! dpkg-query -W -f='${Status}' nvidia-container-toolkit 2>/dev/null | grep -q "ok installed"; then
sudo apt install -y nvidia-container-toolkit
fi
if ! grep -q "nouveau.modeset=0" /etc/default/grub; then
sudo sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="nouveau.modeset=0"/' /etc/default/grub
sudo update-grub
fi
nodeGroups:
- gpu
weight: 5Установка драйвера на CentOS
Протестировано для CentOS 9.
apiVersion: deckhouse.io/v1alpha1
kind: NodeGroupConfiguration
metadata:
name: install-cuda.sh
spec:
bundles:
- centos
content: |
#!/bin/bash
set -e
INSTALL_NEEDED=false
# Установка драйверов (только при первом запуске).
if ! rpm -q nvidia-driver-cuda &> /dev/null; then
dnf install -y curl epel-release dkms gcc make dracut kernel-devel-$(uname -r) elfutils-libelf-devel
dnf config-manager --add-repo https://developer.download.nvidia.com/compute/cuda/repos/rhel9/x86_64/cuda-rhel9.repo
rpm --import https://developer.download.nvidia.com/compute/cuda/repos/GPGKEY
dnf install -y nvidia-driver-cuda nvidia-driver-cuda-libs nvidia-settings nvidia-persistenced
curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | tee /etc/yum.repos.d/nvidia-container-toolkit.repo
dnf install -y nvidia-container-toolkit
INSTALL_NEEDED=true
fi
# Принудительная пересборка модуля для текущего ядра и обновление initramfs.
dkms autoinstall
dracut --force
# Настройка автозагрузки и отключение nouveau.
printf '%s\n' 'nvidia' 'nvidia_uvm' 'nvidia_drm' > /etc/modules-load.d/nvidia.conf
grubby --update-kernel ALL --args="nouveau.modeset=0"
# Ребут, если были изменения.
if [ "$INSTALL_NEEDED" = true ]; then
base64_timer="W1VuaXRdCkRlc2NyaXB0aW9uPWJhc2hpYmxlIHRpbWVyCgpbVGltZXJdCk9uQm9vdFNlYz0xbWluCk9uVW5pdEFjdGl2ZVNlYz0xbWluCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQK"
echo "$base64_timer" | base64 -d | tee /etc/systemd/system/bashible.timer
systemctl enable bashible.timer
base64_bashible="W1VuaXRdCkRlc2NyaXB0aW9uPUJhc2hpYmxlIHNlcnZpY2UKCltTZXJ2aWNlXQpFbnZpcm9ubWVudEZpbGU9L2V0Yy9lbnZpcm9ubWVudApFeGVjU3RhcnQ9L2Jpbi9iYXNoIC0tbm9wcm9maWxlIC0tbm9yYyAtYyAiL3Zhci9saWIvYmFzaGlibGUvYmFzaGlibGUuc2ggLS1tYXgtcmV0cmllcyAxMCIKUnVudGltZU1heFNlYz0zaAo="
echo "$base64_bashible" | base64 -d | tee /etc/systemd/system/bashible.service
systemctl enable bashible.service
systemctl reboot
fi
nodeGroups:
- gpu
weight: 5Установка драйвера на РЕД ОС
Протестировано для РЕД ОС 8.
apiVersion: deckhouse.io/v1alpha1
kind: NodeGroupConfiguration
metadata:
name: install-cuda.sh
spec:
bundles:
- redos
content: |
#!/bin/bash
set -e
INSTALL_NEEDED=false
# Установка драйверов NVIDIA.
if ! rpm -q nvidia-drivers &> /dev/null || ! rpm -q cuda &> /dev/null || ! rpm -q nvidia-persistenced &> /dev/null; then
echo "Update system"
sudo dnf update -y
sudo dnf install -y nvidia-drivers.x86_64 cuda.x86_64 nvidia-persistenced.x86_64
INSTALL_NEEDED=true
fi
# Установка NVIDIA Container Toolkit.
if ! rpm -q nvidia-container-toolkit &> /dev/null; then
echo "NVIDIA container toolkit is not installed. Installing..."
curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
sudo dnf install -y nvidia-container-toolkit
INSTALL_NEEDED=true
fi
# Настройка GRUB и отключение драйвера nouveau.
if ! grep -q "nouveau.modeset=0" /etc/default/grub; then
echo "GRUB configuration and nouveau disabling"
sudo -E grubby --update-kernel ALL --args="nouveau.modeset=0"
sudo grub2-mkconfig -o /boot/grub2/grub.cfg
INSTALL_NEEDED=true
fi
# Создание сервиса bashible, если были установлены драйверы.
if [ "$INSTALL_NEEDED" = true ]; then
base64_timer="W1VuaXRdCkRlc2NyaXB0aW9uPWJhc2hpYmxlIHRpbWVyCgpbVGltZXJdCk9uQm9vdFNlYz0xbWluCk9uVW5pdEFjdGl2ZVNlYz0xbWluCgpbSW5zdGFsbF0KV2FudGVkQnk9bXVsdGktdXNlci50YXJnZXQK"
echo "$base64_timer" | base64 -d | sudo tee /etc/systemd/system/bashible.timer
sudo systemctl enable bashible.timer
base64_bashible="W1VuaXRdCkRlc2NyaXB0aW9uPUJhc2hpYmxlIHNlcnZpY2UKCltTZXJ2aWNlXQpFbnZpcm9ubWVudEZpbGU9L2V0Yy9lbnZpcm9ubWVudApFeGVjU3RhcnQ9L2Jpbi9iYXNoIC0tbm9wcm9maWxlIC0tbm9yYyAtYyAiL3Zhci9saWIvYmFzaGlibGUvYmFzaGlibGUuc2ggLS1tYXgtcmV0cmllcyAxMCIKUnVudGltZU1heFNlYz0zaAo="
echo "$base64_bashible" | base64 -d | sudo tee /etc/systemd/system/bashible.service
sudo systemctl enable bashible.service
sudo systemctl reboot
fi
nodeGroups:
- gpu
weight: 5Установка драйвера на Astra Linux
Протестировано для Astra Linux 1.8.
apiVersion: deckhouse.io/v1alpha1
kind: NodeGroupConfiguration
metadata:
name: install-cuda-astra.sh
spec:
bundles:
- astra
content: |
#!/bin/bash
set -e
export DEBIAN_FRONTEND=noninteractive
# Очистка.
rm -f /etc/apt/sources.list.d/cuda* 2>/dev/null || true
rm -f /etc/apt/sources.list.d/nvidia* 2>/dev/null || true
apt update
apt install -y curl wget linux-headers-$(uname -r) build-essential dkms
# Репозиторий CUDA (Debian 12).
wget -q https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb
dpkg -i cuda-keyring_1.1-1_all.deb
rm -f cuda-keyring_1.1-1_all.deb
apt update
# Репозиторий Container Toolkit.
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' > /etc/apt/sources.list.d/nvidia-container-toolkit.list
apt update
# Установка драйвера 580.
apt install -y nvidia-driver-580 nvidia-settings nvidia-compute-utils-580 nvidia-container-toolkit
# Отключение nouveau.
sed -i 's/GRUB_CMDLINE_LINUX=""/GRUB_CMDLINE_LINUX="nouveau.modeset=0"/' /etc/default/grub
update-grub
nodeGroups:
- gpu
weight: 5После применения конфигурации перезагрузите узлы, затем проверьте драйвер на узле командой nvidia-smi.
Секция Processes в выводе nvidia-smi должна быть пустой до запуска нагрузок. На узлах с графическим окружением GPU часто занят процессами Xorg, gnome-shell, gdm, sddm или lightdm. Такие процессы занимают память GPU и блокируют реконфигурацию MIG и VFIO-проброс.
Как проверить GPU-узел?
Модуль добавляет лейблы на каждый подготовленный узел.
Для получения лейблов используйте команду:
d8 k get node <имя-узла> -o json | jq -r '.metadata.labels | with_entries(select(.key | test("gpu")))'На работающем GPU-узле должны присутствовать все следующие лейблы:
| Лейбл | Значение |
|---|---|
node.deckhouse.io/gpu-setup-complete |
Подготовка узла завершена. Пока лейбла нет, ни один компонент GPU на узел не планируется. |
gpu.deckhouse.io/vendor |
Обнаружен поддерживаемый GPU; значение — его вендор. По этому лейблу планируется соответствующий адаптер. |
node.deckhouse.io/gpu-vfio-ready |
true, если узел готов к VFIO-пробросу. Значение false допустимо, если проброс не нужен. |
Для получения стека, работающего на узле, используйте команду:
d8 k -n d8-nvidia-gpu get pods -o wideПример вывода:
NAME READY STATUS RESTARTS AGE
gpu-controller-7d9f8b6c4-xk2lp 2/2 Running 0 5m
gpu-dcgm-2gflv 1/1 Running 0 5m
gpu-dcgm-exporter-vnjrq 1/1 Running 0 5m
gpu-node-agent-54gk8 1/1 Running 0 5m
nvidia-adapter-8qgqx 3/3 Running 0 5m
Для получения информации об обнаруженном оборудовании используйте команду:
d8 k get physicalgpus -o wideВсе ожидаемые карты должны быть в Ready со значением HEALTHY=True. Колонка HEALTHY —
расширенная, она появляется только с -o wide; вывод по умолчанию заканчивается на AGE и её не содержит.
Для получения информации об устройствах, предложенных планировщику используйте команду:
d8 k get resourceslicesЕсли объекты PhysicalGPU есть, а ResourceSlice нет, значит карты не в фазе Ready: устройства публикуются только в ней. См. Диагностика.
Как опубликовать GPU для пользователей?
Чтобы опубликовать GPU для пользователей, опишите GPUClass, и пользователи смогут запрашивать GPU по имени:
apiVersion: gpu.deckhouse.io/v1alpha1
kind: GPUClass
metadata:
name: a100
spec:
selector:
matchLabels:
gpu.deckhouse.io/device: a100-sxm4-40gbДля просмотра всех DeviceClass, которые были автоматически созданы контроллером GPU на основе GPUClass используйте команду:
d8 k get gpuclass a100 -o jsonpath='{.status.deviceClassNames}' | jqПередайте эти имена пользователям. Фильтры партиций и разделения описаны в разделе Классы GPU.
Как мигрировать с режима Device Plugin на DRA?
Для миграции измените значение параметра dra.enabled с false на true. Миграция выполнится автоматически:
- Хук
check_migrationобнаруживает существующий неймспейсd8-nvidia-gpuи добавляет на него лейблgpu.deckhouse.io/managed-by=gpu. - На следующей реконсиляции
migrationReadyстановитсяtrue, и шаблоны DRA рендерятся. - Helm удаляет стек Device Plugin — device plugin, GFD, MIG-менеджер, DCGM — и разворачивает DRA-стек в том же неймспейсе.
После миграции:
spec.gpuв NodeGroup перестаёт действовать: он больше ничем не управляет. Способ разделения теперь выбирается на уровне нагрузки. Этот параметр можно удалить.- Лейблы узла из режима Device Plugin, такие, как
node.deckhouse.io/device-gpu.configи лейблыnvidia.com/*, опубликованные NFD, могут какое-то время оставаться после удаления NFD. В режиме DRA они игнорируются. - Нагрузки, запрашивающие
nvidia.com/gpu, перестанут планироваться, потому что этот ресурс больше не публикуется. Переведите их на claim’ы до переключения либо запланируйте простой.
Почему DRA-стек вообще не развернулся?
Если после установки значения параметра dra.enabled: true в неймспейсе d8-nvidia-gpu нет ни gpu-controller, ни gpu-node-agent, ни nvidia-adapter, возможно, не выполнено одно из следующих условий для рендеринга шаблонов DRA (они должны выполняться одновременно): dra.enabled, migrationReady и draFeatureGatesReady.
Проверьте статус модуля:
d8 k get module gpu -o jsonpath='{.status.conditions}' | jqЧастая причина — отсутствующие feature gates для DRA. Это отражается как FeatureGatesReady=False с причиной FeatureGatesNotEnabled и алертом D8GpuDraFirstEnablementBlocked. Gates включает платформа, а не модуль, поэтому решение — обновить DKP. Подробнее — в разделе «Готовность feature gates для DRA».
Что случится при отключении Feature gate при работающем DRA?
Появится D8GpuDraFeatureGateDisabledOnComponent. Он появляется, когда необходимый gate отключён на apiserver, планировщике или отдельном kubelet. Интересен именно последний случай: проверка готовности читает только apiserver, поэтому потеря gate kubelet’ом отлавливается этим алертом, а не проверкой готовности.
Что делать, если на GPU-узле нет DRA-подов?
Проверьте лейблы узла:
d8 k get node <имя-узла> -o json | jq -r '.metadata.labels | with_entries(select(.key | test("gpu")))'| Отсутствует или неверно | Значение |
|---|---|
нет node.deckhouse.io/gpu-setup-complete |
Подготовка узла не завершилась. Скорее всего, не прошла проверка драйвера — выполните nvidia-smi на узле. |
нет gpu.deckhouse.io/vendor |
GPU не обнаружен. Проверьте, видна ли карта на шине PCI и работает ли gpu-node-agent. |
gpu.deckhouse.io/enabled=false |
Узел явно исключён из управления GPU. |
gpu.deckhouse.io/maintenance=true |
Узел выведен на обслуживание и исключён намеренно. |
Что делать, если объекты PhysicalGPU есть, а ResourceSlice нет?
Устройства публикуются только, пока карта находится в фазе Ready. Проверьте фазу и условия.
Для просмотра всех физических GPU в кластере используйте команду:
d8 k get physicalgpusДля просмотра условий для конкретного GPU используйте команду:
d8 k get physicalgpu <имя> -o jsonpath='{.status.conditions}' | jqAdapterReady=False с причиной DriverNotReady и сообщением NVML capabilities not available for this device означает, что адаптер не смог обратиться к карте через NVML. Проверьте драйвер на узле и логи контейнера nvidia-adapter:
d8 k -n d8-nvidia-gpu logs daemonset/nvidia-adapter -c nvidia-adapterКарта в фазе Passthrough привязана к vfio-pci и намеренно не предлагается как CUDA-устройство.
Что делать, если под остаётся в Pending, claim не выделяется?
Ни одно опубликованное устройство не удовлетворяет claim. Получите список всех устройств из ресурсов ResourceSlice с их именами и атрибутами:
d8 k get resourceslices -o json | jq '.items[].spec.devices[]? | {name, attributes}'Частые причины проблемы:
- CEL-селектор ничему не соответствует. Типичная ошибка — запрос
sharePercentпри селекторе, исключающем sharing-варианты через!has(...sharingStrategy): эти два условия противоречат друг другу. Подробнее — в разделе «Использование». - Необёрнутый атрибут в CEL. Обращение к необязательному атрибуту без
has(...)приводит к ошибке всего выражения, а не к значению false. - Запрошенный MIG-профиль конфликтует с раскладкой, которую сейчас держит другая нагрузка. Партиции существуют только пока они заняты, поэтому под ждёт завершения держателя. Это планировщик отказывается выделить слайсы карты дважды, а не ошибка.
Что делать, если GPU-нагрузки не работают, хотя драйвер и toolkit установлены?
Факт установки пакетов ничего не гарантирует. В DRA-режиме (dra.enabled: true) модуль проверяет не наличие
компонентов хост-стека GPU, а его работоспособность: загружен ли модуль ядра, отвечает ли nvidia-smi,
совпадают ли версии модуля ядра и драйвера, установлен ли контейнерный toolkit, видит ли GPU
nvidia-container-cli и согласованы ли версии toolkit.
Проверка выполняется ранним шагом bashible на узле и никогда не блокирует конвергенцию узла: узел продолжает получать обновления, а сам шаг не может ни упасть, ни зависнуть (каждый вызов вендорного бинаря ограничен по времени, поэтому зависший модуль ядра не останавливает прогон). Меняется другое:
-
снимается признак готовности
node.deckhouse.io/gpu-setup-complete, поэтому компоненты GPU-стека не едут на неисправный узел. Одного снятия лейбла недостаточно — более поздний шаг подготовки узла в том же прогоне ставит этот лейбл по своему собственному состоянию, — поэтому вердикт дополнительно поднимает локальный bashbooster-флагgpu-host-stack-unhealthy, и именно он заставляет более поздний шаг (gpu-setup.shв DRA-режиме,gpu-sysctl.shв режиме Device Plugin) лейбл не возвращать. Состояние не залипает: и лейбл, и флаг пересчитываются с нуля каждым прогоном подготовки узла, поэтому после починки ничего подчищать руками не нужно; -
на узел ставятся два лейбла с результатом:
d8 k get nodes -L node.deckhouse.io/gpu-host-stack-error,node.deckhouse.io/gpu-host-stack-vendor -
модуль экспортирует метрику
gpu_node_host_stack_unhealthy{node,vendor,reason}и через 15 минут зажигает alertD8GpuNodeHostStackUnhealthy; -
метрика
gpu_node_host_stack_unhealthy_nodesпоказывает число неисправных узлов и публикуется всегда, в том числе со значением0: по ней видно, что проверка выполняется, даже когда неисправных узлов нет.
Драйвер и контейнерный toolkit — внешние предпосылки: модуль их диагностирует, но не устанавливает, не обновляет и не починяет.
Когда выполняется проверка и как запустить её заново?
Это проверка подготовки узла, а не мониторинговая проба. bashible пропускает все шаги, если контрольная сумма конфигурации не изменилась, нет аннотации на перезагрузку и uptime узла вырос, — поэтому вердикт пересчитывается при bootstrap узла, при смене конфигурации (настройки модуля, NodeGroup, обновление Deckhouse) и после перезагрузки, а не по таймеру.
Из этого следуют две вещи:
- поломка, возникшая после успешной конвергенции (например, рассинхрон версий драйвера и toolkit из-за обновления пакетов без перезагрузки), не будет замечена до следующего прогона подготовки узла;
- починка сама по себе вердикт не снимает — проверка должна выполниться заново.
Чтобы заставить перепроверку на узле, перезагрузите узел либо удалите файл контрольной суммы и дождитесь следующего тика bashible:
rm -f /var/lib/bashible/configuration_checksumЭто ограничение касается только программного хост-стека. Состояние самих GPU-устройств отслеживается
непрерывно и независимо от подготовки узла: оно публикуется в PhysicalGPU
(status.driverBinding.mode — наблюдаемый драйвер, status.driverBinding.managementState — кто управляет
устройством), а карта, оставшаяся на бесхозной passthrough-привязке — без владеющего claim и без
объявленного отказа, — классифицируется как Orphaned, продержавшись так двухминутный период
ожидания. Алерт D8GPUPhysicalGPUOrphaned срабатывает ещё позже: у него for: 15m, то есть он
поднимается примерно через семнадцать минут после того, как привязка стала бесхозной, а не через две.
В каком порядке проверять узел?
Выполняйте на самом узле и именно в этом порядке — проверки идут от нижнего уровня стека к верхнему, и первая непройденная указывает на корневую причину:
cat /proc/driver/nvidia/version # загружен ли модуль ядра?
nvidia-smi -L # отвечает ли драйвер?
nvidia-smi --query-gpu=driver_version --format=csv,noheader
nvidia-container-cli info # работает ли контейнерный путь?
nvidia-ctk --version
nvidia-container-cli --version # совпадают ли версии toolkit?Детализация, которой нет в reason-коде, — в логе шага на узле. Где именно лежит этот лог, зависит от версии Deckhouse, а модуль поддерживает обе:
# Deckhouse 1.77 и новее — отдельный файл на каждый шаг bashible:
cat /var/log/d8/bashible/step.006_gpu-check.sh.logНа Deckhouse 1.75 и 1.76 отдельных логов шагов нет. Шаг писал в
/var/lib/bashible/step.log, который перезаписывает каждый следующий шаг, а gpu-check
идёт с weight 6 — поэтому к концу прогона его вывод уже потерян. В этом случае прогоните
проверки выше руками.
Что означают reason-коды NVIDIA?
gpu-host-stack-error |
Что означает | Что делать |
|---|---|---|
host-stack-not-installed |
Узел входит в GPU-NodeGroup, но вендорного хост-стека на нём нет вовсе: ни модуля ядра, ни nvidia-smi, ни контейнерного toolkit. |
Установите на узле драйвер NVIDIA и NVIDIA Container Toolkit либо выведите узел из GPU-NodeGroup. |
driver-not-loaded |
Модуль ядра NVIDIA не загружен или не сообщает версию. | Проверьте dmesg | grep -i nvidia, пересоберите DKMS под текущее ядро, перезагрузите узел. |
nvidia-smi-failed |
Модуль ядра загружен, но nvidia-smi завершается с ошибкой или не показывает ни одного GPU. |
Переустановите драйвер той же версии, что и загруженный модуль ядра. |
driver-version-mismatch |
Загруженный модуль ядра и установленный драйвер разных версий — типичный след DKMS после смены ядра. | Пересоберите модуль ядра под установленный драйвер и перезагрузите узел. |
driver-too-old |
Версия драйвера ниже требуемой 450.80.02. |
Обновите драйвер. |
compute-cap-unsupported |
Compute capability GPU не выше 6.0. |
Карта не поддерживается модулем, используйте более новый GPU. |
toolkit-not-installed |
Отсутствует nvidia-container-runtime или nvidia-container-cli. |
Установите NVIDIA Container Toolkit. На узле GPU-NodeGroup containerd по умолчанию использует runtime nvidia, поэтому без toolkit не запустится ни один контейнер. |
container-cli-failed |
nvidia-container-cli info завершается с ошибкой: libnvidia-container не видит GPU. |
Проверьте SELinux, устройства /dev/nvidia*, CDI-спеку и пакеты nvidia-container*. |
toolkit-version-mismatch |
nvidia-ctk и nvidia-container-cli различаются по major.minor. |
Выровняйте версии пакетов nvidia-container-toolkit, nvidia-container и nvidia-container-tools. |
Reason-коды вендор-специфичны: неисправность определяется парой (gpu-host-stack-vendor,
gpu-host-stack-error). GPU вендоров, для которых проверки пока не реализованы, не проверяются и лейблов
не порождают.
Про узел вне GPU-области проверка ничего не утверждает: если узел не входит ни в одну GPU-NodeGroup и карта в
нём оказалась случайно (control-plane с запасным GPU, хост виртуализации, держащий GPU под passthrough), если
GPU отданы в passthrough драйверу vfio-pci или если GPU поддерживаемого вендора на шине нет вовсе —
reason-кода и alert’а не будет, а вердикт, оставшийся от предыдущего прогона, снимается молча. Поэтому узел не
продолжает алертить после того, как из него вынули карту. Узел, который в GPU-NodeGroup входит, но вендорного
хост-стека не имеет, — случай другой, он сообщается кодом host-stack-not-installed.
После починки следующий прогон подготовки узла снимает оба лейбла gpu-host-stack-*, снимает флаг
gpu-host-stack-unhealthy, возвращает признак готовности, и alert гаснет — как запустить этот прогон, если
починка не потребовала ни перезагрузки, ни смены конфигурации, описано выше.
Что делать в RED OS 7.3 и других дистрибутивах с расходящимися версиями пакетов?
В RED OS MUROM 7.3 репозиторий updates отдаёт сразу несколько версий контейнерных пакетов NVIDIA
(например, nvidia-container-toolkit 1.14.4 рядом с nvidia-container и nvidia-container-tools
1.18.0~rc). Штатная установка спокойно их смешивает: на хосте nvidia-smi работает, карта видна — а в
контейнерах GPU не работает. Это и есть случай toolkit-version-mismatch.
Что проверить:
rpm -qa 'nvidia-container*'
nvidia-ctk --version
nvidia-container-cli --versionВсе пакеты nvidia-container* должны быть одной версии; фиксируйте версию явно при установке, а не
полагайтесь на выбор репозитория по умолчанию. Драйвер устанавливайте по
инструкции NVIDIA по установке драйвера,
контейнерный toolkit — по
инструкции NVIDIA по установке Container Toolkit.
Что делать, если контейнер запустился, но GPU в нём нет?
Самая частая ошибка в манифестах DRA: spec.resourceClaims объявлен, но у контейнера нет соответствующей записи resources.claims. GPU выделяется и просто не передаётся в контейнер — без ошибки, без события и без предупреждения.
spec:
resourceClaims:
- name: gpu
resourceClaimTemplateName: my-claim
containers:
- name: app
resources:
claims:
- name: gpu # Проверьте, что указана эта часть.Что делать, если nvidia-smi внутри пода ничего не находит?
Если у пода нет claim, это корректное поведение. DRA-нагрузки работают в стандартном container runtime и получают устройства только через claim, поэтому под без claim не видит ни одного /dev/nvidia*. Установка NVIDIA_VISIBLE_DEVICES=all ничего не меняет — эта переменная в модуле не действует.
Если claim у пода есть, проверьте запись resources.claims, затем посмотрите, какое устройство было выделено:
d8 k -n <неймспейс> get resourceclaim -o json \
| jq '.items[].status.allocation.devices.results[] | {device, pool}'Что делать, если запрос через extended-ресурс игнорируется?
Под запрашивает gpu.deckhouse.io/<класс> и остаётся в Pending, а ресурс по-прежнему виден в спецификации под.
Мутирующий вебхук, превращающий extended-ресурсы в claim’ы, намеренно не применяется в kube-system и во всех неймспейсах d8-*. Там запрос остаётся без изменений, и поскольку ни один узел его не публикует, под никогда не запланируется. Запускайте GPU-нагрузки в своих неймспейсах.
Если имя класса не существует, вы получите явный отказ:
Error from server (Forbidden): admission webhook "podgpuresourceclaim.gpu.deckhouse.io" denied
the request: get DeviceClass "no-such-class": deviceclasses.resource.k8s.io "no-such-class" not found
Доступные имена смотрите командой d8 k get gpuclass <имя> -o jsonpath='{.status.deviceClassNames}'.
Что делать, если создание или изменение GPUClass отклоняется?
У вебхука GPUClass установлено failurePolicy: Fail, поэтому пока gpu-controller недоступен, запись отклоняется. Проверьте, что он работает:
d8 k -n d8-nvidia-gpu get deploy gpu-controllerПри наличии проблемы появляется ошибка валидации:
partitionFilter value "1g.5gb" must be a DNS label: must not contain dots
Имена профилей в partitionFilter — DNS-метки, пишите 1g5gb (без точки). Форма с точками используется только в CEL-селекторах и в возможностях PhysicalGPU.
Что делать, если в GPUClass нет ожидаемого DeviceClass?
Если ожидаемого имени нет в .status.deviceClassNames, скорее всего оборудование не поддерживает эту комбинацию. Фильтры ограничивают то, что публикуется, но не создают возможности. Проверьте, что карта действительно умеет:
d8 k get physicalgpu <имя> -o jsonpath='{.status.capabilities}' | jqТакже посмотрите .status.matchingPhysicalGPUCount — значение 0 означает, что селектор ничему не соответствует.
Что делать, если выделение GPU зависло?
Каждое опубликованное устройство объявляет bindingConditions: ["Ready"] и bindingFailureConditions: ["BindingFailed"], поэтому неудачная подготовка отражается на claim, а не оставляет под зависшим без оповещений. Проверьте ResourceClaim:
d8 k -n <неймспейс> get resourceclaim <имя> -o yamlОшибки подготовки для VFIO-claim’ов перечислены в разделе «Использование».
Что делать, если вместо разделения MPS получено time-slicing?
Это ожидаемое поведение и об этом сообщается. MPS и time-slicing объявляются на уровне узла, по факту наличия исполняемых файлов вендора — модель карты не проверяется никогда. Поэтому claim с запросом MPS принимается даже на железе, которое его не потянет.
Несоответствие вскрывается при подготовке. Модуль переключается на time-slicing и записывает событие. Для просмотра событий используйте команду:
d8 k -n d8-nvidia-gpu get events --field-selector reason=MPSFallbackToTimeSlicingНагрузка всё равно получит разделение, но не то, которое запрашивала: без MPS нет ограничения потоков на клиента, поэтому sharePercent больше не ограничивает вычисления так, как это было бы под MPS. Если и сам fallback не удался, подготовка останавливается с MPSPrepareFailed.
MPS требует compute capability 7.0 и выше. Подробнее — в разделе «Возможности модуля в зависимости от вендора GPU».
Почему поды DCGM исчезают во время изменения MIG?
Это ожидаемое поведение. Перед реконфигурацией MIG nvidia-adapter выставляет gpu.deploy.dcgm и gpu.deploy.dcgm-exporter в paused-for-mig-change, чтобы DCGM перестал держать GPU. DaemonSet’ы возвращаются после завершения операции.
Что делать, если реконфигурация MIG или VFIO-проброс не выполняются?
Карта должна быть свободна от запущенных процессов. Проверьте на узле:
nvidia-smiСекция Processes должна быть пустой. На узлах с графическим окружением GPU часто занят процессами Xorg, gnome-shell, gdm, sddm или lightdm; они занимают память GPU и блокируют реконфигурацию.
Отдельно для VFIO узлу требуется IOMMU, включённый в BIOS и в командной строке ядра, что отражается значением node.deckhouse.io/gpu-vfio-ready=true.
Что делать, если удаление/отключение модуля зависает?
При удалении хук pre-delete удаляет все объекты PhysicalGPU и ждёт до 600 секунд, чтобы gpu-controller успел снять свои финалайзеры до удаления CRD. Если хук истёк по таймауту, поищите неудаленные объекты PhysicalGPU:
d8 k get physicalgpus -AЧто делать, если GPU отображается как Orphaned?
Если вывод команды d8 k get physicalgpus показывает Management=Orphaned, значит passthrough-привязка драйвера существует без владеющего ResourceClaim и без явного исключения — сегодня это привязка к vfio-pci, единственному драйверу, дающему режим Passthrough, оставшаяся от исчезнувшей нагрузки. Passthrough здесь обязателен, а не типичен: карта с привязкой в режиме Compute и без claim’а — обычная свободная карта, она читается как Unclaimed, пока свободна, и Orphaned не становится никогда. Классификация присваивается только после того, как бесхозная passthrough-привязка продержалась две минуты: это не кратковременное состояние.
Посмотрите причину в условии Managed:
d8 k get physicalgpu <имя> -o jsonpath='{.status.conditions[?(@.type=="Managed")]}' | jqТолько значение Orphaned делает устройство пригодным для reclaim. С каким из восьми случаев вы имеете дело, говорит причина, и каждая из них однозначно задаёт, что стоит в колонке Management:
BackingAllocation→Managed. На карту ссылается выделенныйResourceClaim, она занята.NoBackingAllocation→Unclaimed. Вообще не проблема: карта опознана, привязка живая и вычислительная, никто её не держит. Делать ничего не нужно.ExcludedReleasePending→Managed. Отказ объявлен, но привязка ещё жива, поэтому карта пока не подлежит reclaim.DeliberatelyExcluded→Excluded. Отказ вступил в силу, привязка освобождена.OrphanPending→Unknown. Период ожидания ещё идёт.Orphaned→Orphaned. Бесхозная passthrough-привязка продержалась весь период ожидания — случай, которому посвящён этот раздел.NoLiveBinding→Unknown. Управлять нечем: драйвер не привязан, привязанный не удалось классифицировать либо привязка ещё не опубликована.Indeterminate→Unknown. Прочитать не удалось ничего — нет имени Node или нет PCI-адреса, и достаточно отсутствия любого из двух.
Три причины дают в колонке Unknown; отсчёт из них идёт только у OrphanPending.
Чтобы вернуть устройство, уберите бесхозную passthrough-привязку и дайте обнаружению переклассифицировать его либо запросите сброс, как описано ниже.
Что делать, если запрос reclaim отклонён?
Аннотация gpu.deckhouse.io/reclaim просит контроллер сбросить и заново обнаружить устройство. Запрос, который контроллер выполнить не может, отклоняется, а не игнорируется молча, и отказ записывается в условие Reclaim:
d8 k get physicalgpu <имя> -o jsonpath='{.status.conditions[?(@.type=="Reclaim")]}' | jqУсловие — не постоянная запись. Контроллер снимает его, как только condition Managed переходит после отказа: ответ описывал состояние, которое карта с тех пор покинула, и уходит вместе с ним. Поэтому пустой вывод означает одно из двух — отказов на этой карте не было вовсе либо карта с тех пор сменила состояние. Дольше условия живёт событие ReclaimRefused, до очистки apiserver’ом по --event-ttl (около часа), а после него остаётся лог контроллера, куда отказ пишется всегда:
d8 k get events --field-selector reason=ReclaimRefusedПочти всегда отказ называет колонку Management, а не то, что за ней стоит: reclaim гейтится на managementState раньше всего остального, и допуск открывает только Orphaned. Поэтому сначала читайте колонку — она и решает, что делать:
d8 k get physicalgpusUnclaimed. Отказ верен, и повтор запроса не сработает никогда.Unclaimed— это живаяCompute-привязка, которую никто не держит: здоровая свободная карта, выделяемая как есть, и сбрасывать на ней нечего. Освобождение claim’а на такой карте снова даётUnclaimed, а неOrphaned, поэтому повтор после освобождения зацикливается.Managed. Либо карту держит выделенныйResourceClaim, либо её исключили, пока привязка ещё жива (причинаExcludedReleasePendingусловияManaged). Модуль не отбирает карту у живой нагрузки. Освободите claim и проставляйте аннотацию заново только в том случае, если после этого карта действительно прочиталась какOrphaned: так бывает с бесхозной passthrough-привязкой после периода ожидания, тогда как карта сCompute-привязкой окажется вUnclaimed, и reclaim ей не нужен вовсе.Excluded. Карту сознательно исключили аннотациейgpu.deckhouse.io/unmanaged, и привязка уже освобождена. Сбрасывать нечего; чтобы вернуть карту под управление модуля, снимите аннотацию.Unknownс причинойOrphanPending. Идёт двухминутный период ожидания. Запрос не отклоняется, а удерживается, и reclaim начнётся сам, как только карта станетOrphaned. Дождитесь, а не проставляйте аннотацию заново.Unknownс причинойNoLiveBindingилиIndeterminate. Сбрасывать нечего — живой привязки нет, — либо у объекта нет имени Node или нет PCI-адреса, и достаточно отсутствия любого из двух, так что сопоставлять claim с картой не с чем вовсе. Повторная аннотация ничего не меняет. Сначала восстановите идентичность: проверьте, чтоgpu-node-agentработает на узле и публикуетstatus.nodeInfo.nodeNameиstatus.pciInfo.address.
Отказ можно получить и на карте, которая действительно читается как Orphaned. За гейтом по колонке контроллер ещё раз проверяет занятость и остаётся fail-closed: claim, который всё-таки нашёлся, или занятость, которую установить не удалось, отклоняют запрос уже на этом шаге. Такие отказы редки и означают, что колонка и claim’ы разошлись, — перечитайте и то и другое.
Один терминальный исход в условии Reclaim вообще не является отказом на ваш запрос: если аннотацию сняли, пока сброс шёл, условие фиксирует reclaim как прерванный. Чтобы начать заново, проставьте аннотацию снова.
Почему запрос проброса завершается ошибкой вместо перехода в Passthrough?
VFIO-проброс требует bare-metal-узла. На виртуализированном узле адаптер вендора выставляет AdapterReady=False с причиной VFIORequiresBareMetal, что выводит фазу Failed, а не Passthrough.
Как вывести GPU из-под управления модулем?
Проставьте аннотацию gpu.deckhouse.io/unmanaged. Пока привязка существует, устройство остаётся в Managed с причиной ExcludedReleasePending; после освобождения оно переходит в Excluded.
Как мониторить GPU?
DCGM Exporter разворачивается автоматически, его метрики собирает Prometheus, а дашборды доступны в Grafana — обзор кластера, представления по узлам и неймспейсам, инвентарь GPU и выделения по нагрузкам. Модуль также экспортирует собственные метрики (gpu_inventory_*, gpu_bootstrap_*, gpu_resourceclaim_*). Подробнее — в разделе «Мониторинг».
Поддерживаются ли GPU AMD или Intel?
Для выделения — нет. Адаптеры поставляются для NVIDIA и MetaX, а именно адаптер превращает обнаруженную карту в то, что может запросить рабочая нагрузка.
Всё, что находится выше адаптера, для других вендоров уже работает. Обнаружение распознаёт устройства AMD (1002) и Intel (8086), поэтому их карты появляются как объекты PhysicalGPU с заполненными PCI-данными, а узел получает лейбл gpu.deckhouse.io/vendor=amd или =intel. Без адаптера такие объекты остаются в фазе Pending: их возможности никто не читает, ResourceSlice не публикуется, и планировщик их не видит.
d8 k get physicalgpusNAME NODE MODEL PHASE MANAGEMENT STATUS AGE
worker-2-0-1002-7408 worker-2 Pending Unknown adapter not scheduled to a workload 3m
В колонке MANAGEMENT стоит Unknown с причиной NoLiveBinding. Драйвер amdgpu модуль не
классифицирует, поэтому живой вычислительной привязки у карты нет и управлять модулю нечем.
Сюда карту приводит неклассифицируемый драйвер, а не отсутствие адаптера: карта NVIDIA, для которой
адаптер не запланирован, всё равно привязана к nvidia, всё равно даёт mode: Compute и потому
читается как Unclaimed — та же фаза Pending, другое значение MANAGEMENT. Значение Unclaimed
отведено карте, привязкой которой модуль мог бы управлять и которую никто не взял.
Колонка MODEL читает нормализованный slug модели из лейбла gpu.deckhouse.io/device и остаётся
пустой, пока модель не определена; PCI vendor ID и device ID при этом видны в имени объекта, а
PCI-адрес — в расширенном выводе. Колонка STATUS объясняет, почему карта не в Ready, и
заполняется компонентом gpu-controller: здесь она повторяет сообщение условия
AdapterReady=False/NotScheduled, которое и перевело карту в Pending. Вендор, PCI-адрес и
здоровье устройства тоже показываются в расширенном выводе (d8 k get physicalgpus -o wide).
Добавление вендора не требует изменений ни в CRD, ни в компонентах ядра: нужен контейнер, реализующий контракт адаптера, PCI vendor ID в ConfigMap gpu-supported-vendors и DaemonSet адаптера.
Режим Device Plugin
Всё, что ниже, относится только к режиму Device Plugin (dra.enabled: false).
Как проверить компоненты режима Device Plugin?
Поды NVIDIA в d8-nvidia-gpu:
d8 k -n d8-nvidia-gpu get podОжидаемый корректный вывод (пример):
NAME READY STATUS RESTARTS AGE
gpu-feature-discovery-80ceb7d-r842q 2/2 Running 0 2m53s
nvidia-dcgm-exporter-w9v9h 1/1 Running 0 2m53s
nvidia-dcgm-njqqb 1/1 Running 0 2m53s
nvidia-device-plugin-80ceb7d-8xt8g 2/2 Running 0 2m53s
Поды NFD в d8-nvidia-gpu:
d8 k -n d8-nvidia-gpu get pods | egrep '^(NAME|node-feature-discovery)'Ожидаемый корректный вывод (пример):
NAME READY STATUS RESTARTS AGE
node-feature-discovery-gc-6d845765df-45vpj 1/1 Running 0 3m6s
node-feature-discovery-master-74696fd9d5-wkjk4 1/1 Running 0 3m6s
node-feature-discovery-worker-5f4kv 1/1 Running 0 3m8s
Что делать при наличии ошибки Incompatible strategy detected auto в логах device plugin или GFD?
Ошибки вида Incompatible strategy detected auto, failed to create resource manager: unsupported strategy auto или invalid device discovery strategy означают, что компонент не может определить платформу NVML внутри контейнера — обычно libnvidia-ml.so.* недоступна, потому что не используется runtime из NVIDIA Container Toolkit.
Проверьте (и при необходимости исправьте) следующее:
nvidia-smiработает на узле.- NVIDIA Container Toolkit установлен (существует
/usr/bin/nvidia-container-runtime). - containerd настроен на использование runtime
nvidiaна GPU-узлах. Модуль делает это после установки драйвера и toolkit и перезапуска containerd или перезагрузки узла.
После исправления пересоздайте поды nvidia-device-plugin-* и gpu-feature-discovery-* в неймспейсе d8-nvidia-gpu.
Как посмотреть доступные MIG-профили?
Предопределённые профили лежат в ConfigMap mig-parted-config:
d8 k -n d8-nvidia-gpu get cm mig-parted-config -o json | jq -r '.data["config.yaml"]'В секции mig-configs: перечислены модели GPU по PCI ID и профили, которые поддерживает каждая карта, например all-1g.5gb, all-2g.10gb и all-balanced. Выбранное имя укажите в spec.gpu.mig.partedConfig.
Как задать свой MIG-профиль для каждого GPU на узле?
Используйте partedConfig: custom и опишите партиционирование по индексам GPU:
gpu:
sharing: MIG
mig:
partedConfig: custom
customConfigs:
- index: 0
slices:
- profile: "1g.10gb"
count: 7
- index: 1
slices:
- profile: "2g.20gb"
count: 3Далее модуль генерирует уникальное имя MIG-конфигурации для NodeGroup и выставляет его в лейбле nvidia.com/mig.config, для перечисленных GPU рендерит mig-enabled: true с заданными слайсами, а для каждого неупомянутого индекса — mig-enabled: false, чтобы остальные карты остались в полном режиме.
Что делать, если MIG-профиль не активируется?
Если MIG-профиль не активируется, выполните следующие действия:
-
Проверьте модель GPU. MIG поддерживается на H100, A100 и A30 и не поддерживается на V100 и T4. Подробнее — в таблицах профилей NVIDIA.
-
Убедитесь, что GPU не используется. Подробнее — в разделе «Что делать, если реконфигурация MIG или VFIO-проброс не выполняются».
-
Проверьте конфигурацию NodeGroup.
-
Дождитесь, пока
nvidia-mig-managerвытеснит нагрузку с узла и переконфигурирует GPU. Это может занять несколько минут, в течение которых на узле висит taintmig-reconfigure. -
Следите за прогрессом по лейблу
nvidia.com/mig.config.state:pending,rebooting,successилиfailed. -
Если ресурсы
nvidia.com/mig-*так и не появились, используйте команду:d8 k -n d8-nvidia-gpu logs daemonset/nvidia-mig-manager nvidia-smi -L