Перейти к содержимому
HoginHogin
Назад

GPU в Kubernetes без device plugins: DRA — как теперь правильно выделять ускорители

9 мин чтения

Годами GPU в Kubernetes выделялись по одному числу: nvidia.com/gpu: 1 в resources.limits — и агент на ноде отдавал поду «какой попало» ускоритель. В Kubernetes 1.34 Dynamic Resource Allocation (DRA) вышел в GA, в 1.35+ фича-гейт закреплён навсегда, а NVIDIA перевела свой device plugin в maintenance mode: новые возможности появляются только в DRA-драйвере. Разбираем, как теперь правильно просить GPU — по атрибутам («память ≥ 16 ГБ»), а не по счётчику, и что сломается при переезде.

Содержание

Открыть содержание

Device plugins: почему счётчик — тупик

Device Plugin API появился в 2017-м, когда «GPU в поде» означало «один целый ускоритель». Схема простая: демон на ноде через gRPC-сокет сообщает kubelet список карт, kubelet публикует их как extended resource nvidia.com/gpu, а планировщик видит число — и только число. Про устройства «знает» только агент на ноде: он же монтирует их в контейнер — через переменные вроде NVIDIA_VISIBLE_DEVICES и хуки container toolkit. В API кластера об ускорителях нет ни объекта, ни атрибутов — спросить не у чего: kubectl get по GPU просто нечего вернуть.

Device plugin: планировщик видит только счётчик

Проблемы начинаются там, где GPU перестают быть одинаковыми:

Extended resource не умеет выражать ничего кроме целого числа — это архитектурный потолок API, а не баг, который починят.

Три объекта DRA: ResourceSlice, ResourceClaim, DeviceClass

DRA (API-группа resource.k8s.io/v1) переворачивает модель: вместо счётчика на ноде — инвентарь с атрибутами в API кластера, по которому планирует сам kube-scheduler.

Три объекта DRA: кто создаёт и кто потребляет

Ключевое отличие от ранних прототипов DRA: решения принимает kube-scheduler по структурированным параметрам, без синхронных вызовов внешнего webhook-драйвера — именно из-за них GA и задержался. DRA-драйвер в планировании не участвует: он публикует инвентарь и готовит уже выделенные устройства.

Жизненный цикл у claim человеческий: создан → планировщик нашёл устройства и записал их в status.allocation → pod стартует на выбранной ноде. Устройства в claim зарезервированы за ним: два пода не получат одну карту случайно, а claim можно смотреть, цитировать в тикетах и чистить стандартными средствами kubectl — это полноценный объект API, а не строка в выводе describe node. Работают и приоритеты: при нехватке устройств под с более высоким PriorityClass вытеснит чужой claim — обычный preemption планировщика. Механизм при этом не NVIDIA-специфичный: сетевые адаптеры, FPGA и лицензии заводятся теми же слайсами и классами — просто у NVIDIA драйвер самый зрелый.

Pod с ResourceClaim: как теперь просить GPU

Вместо resources.limits — отдельный объект и ссылка на него в спеке пода.

# gpu-claim.yaml — просим не «единицу GPU», а «карту с памятью от 16 ГБ»
apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: gpu-16gb
spec:
  devices:
    requests:
      - name: gpu
        exactly:
          deviceClassName: gpu.nvidia.com
          allocationMode: Count
          count: 1
          selectors:                        # вместо счётчика — атрибуты
            - cel:
                expression: "device.attributes['gpu.nvidia.com'].memory >= 16000"
# gpu-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: vectoradd
spec:
  runtimeClassName: nvidia
  containers:
    - name: cuda
      image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.1
      command: ["./vectorAdd"]
  resourceClaims:                 # ← то, что заменило nvidia.com/gpu
    - name: gpu
      source:
        resourceClaimName: gpu-16gb
  resources:
    claims:
      - name: gpu                  # устройство доступно контейнерам

CEL-селектор комбинирует условия: модель (productName), память, версию драйвера. Для Job и других многоподовых нагрузок claim удобнее не создавать руками, а генерировать шаблоном — каждый под получит собственный:

# claim-template.yaml — под-специфичный claim из шаблона
apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: gpu-16gb-tpl
spec:
  spec:
    devices:
      requests:
        - name: gpu
          exactly:
            deviceClassName: gpu.nvidia.com
            allocationMode: Count
            count: 1
            selectors:
              - cel:
                  expression: "device.attributes['gpu.nvidia.com'].memory >= 16000"

В поде вместо resourceClaimName — resourceClaimTemplateName: gpu-16gb-tpl: контроллер создаст claim с уникальным именем и удалит его вместе с подом. Отдельный shared-claim (как в примере выше) подходит, когда один выделенный GPU честно делят несколько подов.

Что нужно, чтобы перевести кластер на DRA

Нужны Kubernetes ≥ 1.34, NVIDIA GPU Operator и DRA-драйвер. Перед стартом проверьте три вещи: версию control plane (kubectl version), что container runtime — containerd или CRI-O (DRA-механика доставки устройств опирается на CDI), и что у вас нет софта, который безусловно требует nvidia.com/gpu в лимитах пода — старые версии Kubeflow и платформенные контроллеры иногда валидируют именно его. На managed-кластерах убедитесь, что control plane уже обновлён: апгрейд может идти по расписанию провайдера. Порядок такой.

1. GPU Operator без device plugin — драйвер GPU, toolkit и DCGM-exporter ставятся как обычно, а плагин выключаем:

helm upgrade --install gpu-operator nvidia/gpu-operator \
  --namespace gpu-operator --create-namespace \
  --set driver.enabled=true \
  --set devicePlugin.enabled=false

2. DRA-драйвер NVIDIA — публикует ResourceSlice и DeviceClass, генерирует CDI-спеки:

helm repo add nvidia https://helm.ngc.nvidia.com/nvidia --force-update
helm upgrade --install nvidia-dra-driver nvidia/k8s-dra-driver \
  --namespace nvidia-dra-driver --create-namespace \
  --set runtimeClassName=nvidia

Свежие релизы GPU Operator умеют ставить DRA-драйвер тем же чартом — если ваша версия так умеет, второй шаг не нужен.

3. CDI в container runtime. Устройства попадают в контейнер через CDI: драйвер пишет спеку с точным списком (nvidia.com/gpu=2), containerd/CRI-O монтируют в контейнер ровно это. Нужен containerd ≥ 1.7 с enable_cdi = true (в containerd 2.0 включено по умолчанию). Быстрая проверка, что runtime готов: crictl info | grep -i cdi.

Drain нод не нужен: существующие поды с nvidia.com/gpu продолжают работать по старому пути, пока вы их не переехали, — API device plugin никто не удалял.

DRA против device plugins

Device pluginDRA
Что просит подnvidia.com/gpu: 1 — числоResourceClaim с атрибутами
Кто выбирает устройствоагент на ноде, «какое попало»kube-scheduler по инвентарю
MIGпере-публикация и гонкислайсы — устройства с атрибутами
Sharingневидимый оверсабскрипшнчестные доли у планировщика
Квоты и мониторингextended resource в kubeletResourceSlice/claim в API кластера
Требования к кластерулюбая версия Kubernetes≥ 1.34, containerd/CRI-O с CDI
Статусmaintenance mode у NVIDIAGA в 1.34, гейт locked в 1.35+

Что ломается при миграции

Сам переезд мягкий — старые поды живут, — но обвязка вокруг счётчиков переезжать отказывается.

Что ломается при переезде на DRA

apiVersion: v1
kind: ResourceQuota
metadata:
  name: gpu-claims
spec:
  hard:
    count/resourceclaims.resource.k8s.io: "4"

Когда DRA реально даёт выигрыш

Если все карты одинаковые и один под занимает карту целиком, DRA ничего революционного не даст — только соответствие стандарту. Выигрыш появляется на неоднородном железе:

Как проверить, что всё работает

После установки драйвера:

kubectl get resourceslices                      # инвентарь опубликован
kubectl describe deviceclass gpu.nvidia.com     # какие атрибуты можно селектить
kubectl apply -f gpu-claim.yaml
kubectl get resourceclaim gpu-16gb              # allocation: конкретная карта
kubectl get pod vectoradd -w                    # Pending → Running
kubectl exec vectoradd -- nvidia-smi -L         # под видит ровно выданное
kubectl describe resourceclaim gpu-16gb         # атрибуты и выделенное устройство

Если под висит в Pending — kubectl describe pod: в events будет причина, например «no devices match selector» — селектор строже инвентаря. А если kubectl get resourceslices пуст — смотрите логи подов nvidia-dra-driver: без драйвера инвентарь не появится.

Итог

Device plugins для GPU — легаси: NVIDIA развивает только DRA-драйвер, а в 1.35+ фича-гейт закреплён навсегда. Плата за переезд — переписать пару квот и дашбордов; выигрыш — планировщик, который видит MIG, шаринг и объём памяти, вместо лотереи «первый попавшийся». Мигрировать лучше сейчас, пока оба пути работают параллельно: поднимите DRA-драйвер рядом с плагином, переведите некритичные Job-ы, перепишите квоты и дашборды — и только потом выключайте device plugin, namespace за namespace. А если у вас на кластере уже живёт observability-стек — audit-логи Kubernetes в Wazuh мы разбирали отдельно.


Поделиться:

Следующая статья
Форма обратной связи на статическом сайте: Cloudflare Turnstile + Pages Functions + D1 + Telegram — без своего бэкенда