Запуск ВМ с пробросом GPU (passthrough)
В этом разделе показано, как развёртывать виртуальные машины (ВМ) с пробросом GPU (passthrough) с помощью Cozystack. Сначала мы развернём GPU Operator, чтобы настроить рабочий узел для проброса GPU (passthrough) Затем мы развернём ВМ KubeVirt, запрашивающую GPU.
По умолчанию для обеспечения проброса GPU (passthrough) GPU Operator развёртывает следующие компоненты:
- VFIO Manager для привязки драйвера
vfio-pciко всем GPU на узле. - Sandbox Device Plugin для обнаружения проброшенных GPU и их анонсирования kubelet.
- Sandbox Validator для проверки остальных операндов.
Предварительные требования
- Кластер Cozystack с хотя бы одним узлом с поддержкой GPU.
- Установленный kubectl и настроенные учётные данные для доступа к кластеру.
1. Установка GPU Operator
Выполните следующие шаги:
Явно пометьте рабочий узел меткой для рабочих нагрузок с пробросом GPU (passthrough):
kubectl label node <node-name> --overwrite nvidia.com/gpu.workload.config=vm-passthroughВключите GPU Operator в вашем Platform Package, добавив его в список включённых пакетов:
kubectl patch packages.cozystack.io cozystack.cozystack-platform --type=json \ -p '[{"op": "add", "path": "/spec/components/platform/values/bundles/enabledPackages/-", "value": "cozystack.gpu-operator"}]'Это развернёт компоненты (операнды).
Убедитесь, что все поды находятся в состоянии running и все проверки компонента sandbox-validator проходят успешно:
kubectl get pods -n cozy-gpu-operatorПример вывода (имена ваших подов могут отличаться):
NAME READY STATUS RESTARTS AGE ... nvidia-sandbox-device-plugin-daemonset-4mxsc 1/1 Running 0 40s nvidia-sandbox-validator-vxj7t 1/1 Running 0 40s nvidia-vfio-manager-thfwf 1/1 Running 0 78s
Чтобы проверить привязку GPU, получите доступ к узлу с помощью kubectl node-shell -n cozy-system -x или kubectl debug node и выполните:
lspci -nnk -d 10de:
Под vfio-manager привяжет все GPU на узле к драйверу vfio-pci. Пример вывода:
3b:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2236] (rev a1)
Subsystem: NVIDIA Corporation Device [10de:1482]
Kernel driver in use: vfio-pci
86:00.0 3D controller [0302]: NVIDIA Corporation Device [10de:2236] (rev a1)
Subsystem: NVIDIA Corporation Device [10de:1482]
Kernel driver in use: vfio-pci
sandbox-device-plugin обнаружит эти ресурсы и анонсирует их kubelet. В этом примере узел показывает два GPU A10 как доступные ресурсы:
kubectl describe node <node-name>
Пример вывода:
...
Capacity:
...
nvidia.com/GA102GL_A10: 2
...
Allocatable:
...
nvidia.com/GA102GL_A10: 2
...
device и device_name из
базы данных PCI IDs.
Например, запись в базе данных для A10 выглядит как 2236 GA102GL [A10], что приводит к имени ресурса nvidia.com/GA102GL_A10.2. KubeVirt подключается автоматически
Когда cozystack.gpu-operator присутствует в bundles.enabledPackages, Cozystack автоматически зеркалирует выбранный вариант GPU в Custom Resource KubeVirt. Шаг kubectl edit kubevirt не требуется.
В частности, платформа внедряет:
HostDevicesвspec.configuration.developerConfiguration.featureGates(текущий KubeVirt отделяет это от гейтаGPU; admission webhook отклоняетdomain.devices.hostDevicesбез него).- Начальную таблицу
spec.configuration.permittedHostDevices.pciHostDevices(рендерится в дефолтном вариантеgpuOperatorVariant: default- passthrough через vfio-pci), покрывающую распространённые дата-центровые GPU NVIDIA - Hopper (H100, H200), Ada Lovelace (L4, L40, L40S), Ampere (A100 PCIe/SXM, A40, A30, A10), Turing (T4), Volta (V100, V100S). Пары PCI vendor:device стабильны; каждый слагresourceName- это то, чтоnvidia-sandbox-device-pluginмеханически выводит из имени карты в базе PCI-IDs - переводит имя в верхний регистр, заменяет/,.и пробелы на_, затем убирает окружающие[/]. Таким образом слаг несёт в себе каждый токен из строки PCI-IDs (суффикс кристаллаGL, брендTeslaна Turing/Volta, форм-фактор, объём памяти), а не аккуратный<arch>_<model>:TU104GL [Tesla T4]становитсяnvidia.com/TU104GL_TESLA_T4,GA100GL [A30 PCIe]становитсяnvidia.com/GA100GL_A30_PCIE, а H200 SXM становитсяnvidia.com/GH100_H200_SXM_141GB. Уточните точные строки, которые анонсируют ваши узлы, с помощьюkubectl describe node <node> | grep nvidia.com/.externalResourceProvider: trueустанавливается для каждой записи, потому что ресурсы анонсируются sandbox-плагином, а не встроенным device-плагином KubeVirt.
Проверьте итоговый CR:
kubectl -n cozy-kubevirt get kubevirt kubevirt -o json \
| jq '.spec.configuration | {featureGates: .developerConfiguration.featureGates, permittedHostDevices: .permittedHostDevices}'
kubectl edit kubevirt? Он убран намеренно. permittedHostDevices теперь принадлежит шаблону чарта и реконсилируется из значений платформы, поэтому любое ручное изменение живого CR будет откачено при следующей реконсиляции Flux/Helm. Добавьте свою карту через .gpu.permittedHostDevices вместо этого - см.
Расширение или замена дефолтов NVIDIA ниже. Если вы обновляетесь с релиза, где вы вручную редактировали CR, сначала выполните
Обновление с вручную отредактированного KubeVirt CR.Расширение или замена дефолтов NVIDIA
Если ваш кластер использует GPU, отсутствующий в дефолтной таблице, или ваша версия nvidia-sandbox-device-plugin выдаёт другой resourceName (проверьте с помощью kubectl describe node <node> | grep nvidia.com/), расширьте дефолты через значения платформы:
# Platform Package values
gpu:
# Append (по умолчанию) - ваши записи добавляются к таблице NVIDIA.
# Установите true, чтобы полностью убрать таблицу NVIDIA (полезно для
# кластеров, работающих только с не-NVIDIA GPU, или для строгих
# allowlist-ов). При replaceDefaults: true и пустом списке ниже
# итоговый CR не будет содержать блок permittedHostDevices вовсе,
# и admission webhook отклонит каждую GPU VM - предоставьте свой список.
replaceDefaults: false
permittedHostDevices:
pciHostDevices:
- pciVendorSelector: "10DE:2236"
resourceName: nvidia.com/GA102GL_A10
externalResourceProvider: true
Чтобы перенаправить карту, уже присутствующую в таблице NVIDIA (например, чтобы дать 10DE:1EB8 другой resourceName), не добавляйте вторую запись для того же pciVendorSelector - обе записи будут отрендерены, и KubeVirt разрешает дублированный селектор недетерминированно. Установите replaceDefaults: true и предоставьте полный список, который вы хотите использовать вместо этого.
Обновление с вручную отредактированного KubeVirt CR
В более ранних релизах Cozystack spec.configuration.permittedHostDevices оставлялся операторам для ручного редактирования (kubectl edit kubevirt). Теперь бандл владеет этим полем: первая реконсиляция после обновления заменяет ваши ручные записи отрендеренной дефолтной таблицей NVIDIA.
Перед обновлением:
Выгрузите текущие записи:
kubectl -n cozy-kubevirt get kubevirt kubevirt -o json \ | jq '.spec.configuration.permittedHostDevices'Перенесите любые кастомные записи в значения Platform Package под
.gpu.permittedHostDevices(установите.gpu.replaceDefaults: true, если хотите только свой список вместо добавления к дефолтам NVIDIA).Проверьте каждый
resourceNameотносительно того, что реально анонсируют ваши узлы. Дефолтная таблица содержит слаг, который генерируетnvidia-sandbox-device-pluginиз имени карты в PCI-IDs (в верхнем регистре, например,nvidia.com/TU104GL_TESLA_T4для Tesla T4), но другая сборка плагина или снапшот PCI-IDs может выдать другую строку:kubectl describe node <node> | grep nvidia.com/
Несовпадение resourceName остаётся незаметным до тех пор, пока GPU VM не перезапустится или не мигрирует, после чего admission webhook отклоняет её.
Путь ручного переопределения Package-CR
Если вы отказываетесь от управления бандлом и создаёте Package CR cozystack.gpu-operator вручную (чтобы применить переопределения, которые бандл не предоставляет - настройки драйвера, кастомные node selectors, настройки validator / dcgmExporter), платформа НЕ автоматически подключает HostDevices или permittedHostDevices в CR KubeVirt. В этом случае воспроизведите поведение бандла, также создав Package CR cozystack.kubevirt, который несёт extraFeatureGates и соответствующий блок permittedHostDevices под spec.components.kubevirt.values (cozystack Package всегда вкладывает значения компонента под spec.components.<name>.values, никогда не в верхнеуровневый spec.values):
apiVersion: cozystack.io/v1alpha1
kind: Package
metadata:
name: cozystack.kubevirt
spec:
variant: default
components:
kubevirt:
values:
extraFeatureGates:
- HostDevices
permittedHostDevices:
pciHostDevices:
- pciVendorSelector: "10DE:2236"
resourceName: nvidia.com/GA102GL_A10
externalResourceProvider: true
Путь ручного переопределения Package-CR имеет приоритет над рендером бандла, когда существуют оба варианта.
3. Создание виртуальной машины
Теперь мы готовы создать ВМ.
Создайте тестовую виртуальную машину с помощью следующей спецификации VMI, которая запрашивает ресурс
nvidia.com/GA102GL_A10.vmi-gpu.yaml:
--- apiVersion: apps.cozystack.io/v1alpha1 appVersion: '*' kind: VirtualMachine metadata: name: gpu namespace: tenant-example spec: running: true instanceProfile: ubuntu instanceType: u1.medium systemDisk: image: ubuntu storage: 5Gi storageClass: replicated gpus: - name: nvidia.com/GA102GL_A10 cloudInit: | #cloud-config password: ubuntu chpasswd: { expire: False }kubectl apply -f vmi-gpu.yamlПример вывода:
virtualmachines.apps.cozystack.io/gpu createdПроверьте статус ВМ:
kubectl get vmiNAME AGE PHASE IP NODENAME READY virtual-machine-gpu 73m Running 10.244.3.191 luc-csxhk-002 TrueВойдите в ВМ и убедитесь, что у неё есть доступ к GPU:
virtctl console virtual-machine-gpuПример вывода:
Successfully connected to vmi-gpu console. The escape sequence is ^] vmi-gpu login: ubuntu Password: ubuntu@virtual-machine-gpu:~$ lspci -nnk -d 10de: 08:00.0 3D controller [0302]: NVIDIA Corporation GA102GL [A10] [10de:26b9] (rev a1) Subsystem: NVIDIA Corporation GA102GL [A10] [10de:1851] Kernel driver in use: nvidia Kernel modules: nvidiafb, nvidia_drm, nvidia
Совместное использование GPU виртуальными машинами
Проброс GPU (passthrough) назначает весь физический GPU одной ВМ. Чтобы разделить один GPU между несколькими ВМ, требуется NVIDIA vGPU.
vGPU (виртуальный GPU)
NVIDIA vGPU - единственное готовое к production-использованию решение для совместного использования GPU между виртуальными машинами. Существует две модели на стороне хоста в зависимости от поколения GPU: mediated devices (mdev) для Pascal — Ampere, и SR-IOV virtual functions для Ada Lovelace и новее. См. NVIDIA vGPU для виртуальных машин для полной информации по настройке, включая назначение профилей и лицензирование DLS.
Требования:
- Лицензия NVIDIA vGPU (коммерческая, приобретается у NVIDIA)
- NVIDIA vGPU Manager, установленный на узлах-хостах
Open-Source vGPU (экспериментально)
NVIDIA разрабатывает поддержку vGPU с открытым исходным кодом для ядра Linux. После её включения это может обеспечить совместное использование GPU без лицензии.
- Статус: стадия RFC, не включено в основную ветку ядра
- Поддерживает Ada Lovelace и новее (L4, L40 и т. д.)
- Ссылки: анонс Phoronix, патчи ядра