Як працює DRA

Ця сторінка описує, як Kubernetes виділяє пристрої робочим навантаженням за допомогою динамічного виділення ресурсів (DRA) і як попередньо заплановані Podʼи взаємодіють з цим процесом.

Як працює розподіл ресурсів з DRA

Наступні розділи описують робочий процес для різних типів користувачів DRA та для системи Kubernetes під час динамічного розподілу ресурсів.

Робочий процес для користувачів

  1. Створення драйвера: власники пристроїв або сторонні організації створюють драйвери, які можуть створювати та керувати ResourceSlices у кластері. Ці драйвери за бажанням також створюють DeviceClasses, які визначають категорію пристроїв та як їх запитувати.
  2. Конфігурація кластера: адміністратори кластера створюють кластери, підключають пристрої до вузлів і встановлюють драйвери пристроїв DRA. Адміністратори кластера за бажанням створюють DeviceClasses, які визначають категорії пристроїв та як їх запитувати.
  3. Запити на ресурси: оператори навантаження створюють ResourceClaimTemplates або ResourceClaims, які запитують конкретні конфігурації пристроїв у межах DeviceClass. На тому ж етапі оператори навантаження модифікують свої Kubernetes маніфести, щоб запитувати ці ResourceClaimTemplates або ResourceClaims.

Робочий процес для Kubernetes

  1. Створення ResourceSlice: драйвери в кластері створюють ResourceSlices, які представляють один або кілька пристроїв у керованому пулі подібних пристроїв.

  2. Створення навантаження: панель управління кластера перевіряє нові навантаження на наявність посилань на ResourceClaimTemplates або на конкретні ResourceClaims.

    • Якщо навантаження використовує ResourceClaimTemplate, контролер з імʼям resourceclaim-controller генерує ResourceClaims у навантаженні.
    • Якщо навантаження використовує конкретний ResourceClaim, Kubernetes перевіряє, чи існує цей ResourceClaim у кластері. Якщо ResourceClaim не існує, Podʼи не будуть розгорнуті.
  3. Фільтрація ResourceSlice: для кожного Podʼа Kubernetes перевіряє ResourceSlices у кластері, щоб знайти пристрій, який задовольняє всі наступні критерії:

    • Вузли, які можуть отримати доступ до ресурсів, мають право запускати Pod.
    • ResourceSlice має нерозподілені ресурси, які відповідають вимогам ResourceClaim Podʼа.
  4. Виділення ресурсів: після знаходження відповідного ResourceSlice для ResourceClaim Podʼа, планувальник Kubernetes оновлює ResourceClaim з деталями виділення ресурсів. Планувальник використовує стратегію першого підходящого варіанту та оцінює пули та ResourceSlices у лексикографічному порядку за їхніми іменами. Драйвери можуть пріоритизувати конкретні slices або пули, відповідно називаючи їх. Для отримання додаткової інформації див. Іменування та пріоритизація.

  5. Планування Podʼів: коли виділення ресурсів завершено, планувальник розміщує Podʼи на вузлі, який може отримати доступ до виділеного ресурсу. Драйвер пристрою та kubelet на цьому вузлі координуються через gRPC, щоб налаштувати пристрій і доступ Podʼа до пристрою, якщо драйвер не оголосив необовʼязкові операції з вузлами для пристроїв, які не потребують локальної підготовки або очищення на вузлі.

Попередньо заплановані Podʼи

Коли ви, або інший клієнт API, створюєте Pod із вже встановленим spec.nodeName, планувальник пропускається. Якщо будь-який ResourceClaim, потрібний для цього Podʼа, ще не існує, не виділений або не зарезервований для Podʼа, то kubelet не зможе запустити Pod і періодично перевірятиме це, оскільки ці вимоги можуть бути задоволені пізніше.

Така ситуація також може виникнути, коли підтримка динамічного виділення ресурсів не була увімкнена в планувальнику на момент планування Podʼа (різниця версій, конфігурація, функціональна можливість і т. д.). kube-controller-manager виявляє це і намагається зробити Pod працюючим, шляхом резервування потрібних ResourceClaims. Однак, це працює лише якщо вони були виділені планувальником для якогось іншого Podʼа.

Краще уникати оминання планувальника, оскільки Pod, який призначений для вузла, блокує нормальні ресурси (памʼять, CPU), які потім не можуть бути використані для інших Podʼів, поки Pod застряг. Щоб запустити Pod на певному вузлі, при цьому проходячи через звичайний потік планування, створіть Pod із селектором вузла, який точно відповідає бажаному вузлу:

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-cats
spec:
  nodeSelector:
    kubernetes.io/hostname: name-of-the-intended-node
  ...

Можливо, ви також зможете змінити вхідний Pod під час допуску, щоб скасувати поле .spec.nodeName і використовувати селектор вузла замість цього.

Умови привʼязки пристрою

Стан функціоналу: Beta починаючи з Kubernetes v1.36; стандартно увімкнено

Умови привʼязки пристрою дозволяють планувальнику Kubernetes затримувати привʼязку Podʼа до тих пір, поки зовнішні ресурси, такі як GPU з підключенням до фабрики або перепрограмовані FPGA, не будуть підтверджені як готові.

Ця поведінка очікування реалізована в фазі PreBind фреймворку планування. Під час цієї фази планувальник перевіряє, чи всі необхідні умови пристрою є виконаними, перш ніж продовжити з привʼязкою.

Це покращує надійність планування, уникаючи передчасної привʼязки, і дозволяє координацію з зовнішніми контролерами пристроїв.

Щоб використовувати цю функцію, драйвери пристроїв (зазвичай керовані власниками драйверів) повинні опублікувати наступні поля в розділі Device ResourceSlice. Адміністратори кластерів повинні увімкнути функціональні можливості DRADeviceBindingConditions і DRAResourceClaimDeviceStatus, щоб планувальник міг враховувати ці поля.

bindingConditions
Список типів станів, які повинні бути встановлені в True (у полі .status.conditions асоційованого ResourceClaim), перш ніж Pod може бути привʼязаний. Ці стани зазвичай представляють сигнали готовності, такі як DeviceAttached або DeviceInitialized.
bindingFailureConditions
Список типів станів, які, якщо встановлені в True у полі status.conditions асоційованого ResourceClaim, вказують на стан збою. Якщо будь-який з цих станів є True, планувальник скасує привʼязку та перенаправить Pod.
bindsToNode
якщо встановлено в true, планувальник записує вибране імʼя вузла в полі status.allocation.nodeSelector асоційованого ResourceClaim. Це не впливає на spec.nodeSelector Podʼа. Натомість він встановлює селектор вузла всередині ResourceClaim, який зовнішні контролери можуть використовувати для виконання специфічних для вузла операцій, таких як підключення або підготовка пристроїв.

Усі типи станів, перераховані в bindingConditions і bindingFailureConditions, оцінюються з поля status.conditions асоційованого ResourceClaim. Зовнішні контролери відповідають за оновлення цих станів, використовуючи стандартну семантику станів Kubernetes (type, status, reason, message, lastTransitionTime).

Планувальник чекає до 600 секунд (стандартно), щоб усі bindingConditions стали True. Якщо тайм-аут досягається або будь-які bindingFailureConditions є True, планувальник очищає виділення та перенаправляє Pod. Адміністратор кластера може налаштувати тривалість цього тайм-ауту, редагуючи файл конфігурації kube-scheduler.

Приклад налаштування цього тайм-ауту в KubeSchedulerConfiguration наведено нижче:

apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- schedulerName: default-scheduler
  pluginConfig:
  - name: DynamicResources
    args:
      apiVersion: kubescheduler.config.k8s.io/v1
      kind: DynamicResourcesArgs
      bindingTimeout: 60s

Приклад

Нижче наведено приклад ResourceSlice, який ви можете побачити в кластері, де використовується драйвер DRA, і цей драйвер підтримує умови привʼязки:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: gpu-slice-1
spec:
  driver: dra.example.com
  nodeSelector:
    nodeSelectorTerms:
    - matchExpressions:
      - key: accelerator-type
        operator: In
        values:
        - "high-performance"
  pool:
    name: gpu-pool
    generation: 1
    resourceSliceCount: 1
  devices:
    - name: gpu-1
      attributes:
        vendor:
          string: "example"
        model:
          string: "example-gpu"
      bindsToNode: true
      bindingConditions:
        - dra.example.com/is-prepared
      bindingFailureConditions:
        - dra.example.com/preparing-failed

Цей приклад ResourceSlice має такі властивості:

  • ResourceSlice націлений на вузли з міткою accelerator-type=high-performance, щоб планувальник використовував лише певний набір допустимих вузлів.
  • Планувальник вибирає один вузол з обраної групи (наприклад, node-3) і встановлює поле status.allocation.nodeSelector в ResourceClaim на це імʼя вузла.
  • Стан привʼязки dra.example.com/is-prepared вказує на те, що пристрій gpu-1 повинен бути підготовлений (стан is-prepared має статус True) перед привʼязкою.
  • Якщо підготовка пристрою gpu-1 не вдалася (стан preparing-failed має статус True), планувальник скасовує привʼязку.
  • Планувальник чекає до 600 секунд (стандартно), щоб пристрій став готовим.
  • Зовнішні контролери можуть використовувати селектор вузла в ResourceClaim для виконання операцій, специфічних для вузла, на вибраному вузлі.

Стани привʼязки пристроїв контролюються функціональною можливістю DRADeviceBindingConditions у kube-apiserver та kube-scheduler.

Ресурси вузла, доступні для виділення

Стан функціоналу: Alpha починаючи з Kubernetes v1.36; стандартно вимкнено
Докладніше про цей функціонал

Щоб скористатися цією функцією, вам (або адміністратору кластера) потрібно увімкнути функціональну можливість DRANodeAllocatableResources для всіх відповідних компонентів у вашому кластері.

Перегляньте Увімкнення або вимкнення функціональних можливостей для отримання додаткової інформації.

Пристрої, що управляються DRA, можуть мати базову конфігурацію, яка складається з ресурсів, що розподіляються на рівні вузлів, таких як cpu, memory або hugepages. Ця функція інтегрує ці запити на основі DRA у стандартний розрахунок планувальника поряд зі звичайними запитами spec Podʼа на ці ресурси.

Драйвери DRA визначають, як пристрої споживають ресурси вузла, доступні для виділення, за допомогою двох різних моделей:

  • Пряме зіставлення ресурсів (mapping): пристрій DRA безпосередньо надає стандартний ресурс вузла (такий як власний пул ядер CPU або блок памʼяті). Розподіл ресурсів безпосередньо відповідає стандартній потужності CPU або памʼяті на вузлі.
  • Допоміжні накладні витрати пристрою (overhead): пристрій DRA (такий як GPU або прискорювач) потребує ресурсів хосту (таких як оперативна памʼять хосту) як вторинних накладних витрат для роботи, коли його виділено для Podʼа або контейнера.

Рекомендації для авторів Podʼів

При створенні PodSpec з використанням заявок для цих типів пристроїв слід враховувати кілька моментів:

  • Коли використовуються ресурси на рівні Podʼа, планувальник суворо перевіряє їх як для запитів, так і для лімітів контейнерів:
    • Сума всіх запитів контейнерів і ресурсів заявок DRA не повинна перевищувати запити на рівні Podʼа; в іншому випадку Pod не зможе бути запланований.
    • Ліміт кожного окремого контейнера плюс його виділення DRA не повинні перевищувати ліміти на рівні Podʼа; в іншому випадку Pod не зможе бути запланований.
  • Загальна потреба контейнера в ресурсах є сумою його ресурсів на рівні контейнера та будь-яких ресурсів вузла з повʼязаних заявок на ресурс.
  • Обмеження спільного використання заявок: заявки, що використовують пряме зіставлення ресурсів (mapping), не можуть бути спільними між кількома Podʼами. Заявки для пристроїв з overhead можуть підтримувати спільне використання пристроїв, і накладні витрати відстежуються для кожного Podʼа або контейнера окремо.
  • Podʼи із заявками DRA підтримують зміну розміру на місці для стандартних запитів у spec. Планувальник забезпечує, щоб змінені стандартні запити разом зі статичними виділеннями DRA все ще вміщувалися на вузлі.

Деталі для авторів драйверів DRA

Драйвери DRA оголошують цю базову конфігурацію ресурсів вузла, доступних для виділення, за допомогою поля nodeAllocatableResources для пристроїв у ResourceSlice. Це визначає перетворення запитуваного пристрою DRA або ємності у стандартні ресурси, які відстежуються у полі status.allocatable вузла (зверніть увагу, що розширені ресурси для цього поля не підтримуються). Це корисно як для драйверів, які безпосередньо надають власні ресурси (наприклад, драйвер DRA для CPU або памʼяті), так і для пристроїв, які потребують допоміжних залежностей від вузла (наприклад, прискорювач, якому потрібна памʼять хоста).

Поле nodeAllocatableResources підтримує два різні випадки використання:

  • Зіставлення: використовується, коли пристрій DRA безпосередньо представляє стандартний ресурс (наприклад, драйвер DRA для CPU або памʼяті). Планувальник обчислює точну кількість, масштабуючи ємність за допомогою capacityMultiplier або масштабуючи кількість пристроїв за допомогою deviceMultiplier.
  • Накладні витрати: використовується, коли пристрій потребує допоміжних залежностей від вузла (наприклад, памʼять хоста, яку споживає GPU). Це може бути визначено як фіксована вартість perPod або змінна вартість perContainer, яка масштабується лінійно з кількістю контейнерів, що посилаються на пристрій.

Приклад: драйвер CPU DRA (Зіставлення)

Ось приклад, де драйвер CPU DRA відкриває сокет CPU як пул з 128 CPU, використовуючи споживчу ємність DRA. capacityKey повʼязує споживану ємність cpu.example.com/cpu безпосередньо зі стандартним ресурсом cpu, доступним на вузлі:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: my-node-cpus
spec:
  driver: cpu.example.com
  nodeName: my-node
  pool:
    name: socket-cpus
    generation: 1
    resourceSliceCount: 1
  devices:
  - name: socket0cpus
    allowMultipleAllocations: true
    capacity:
      "cpu.example.com/cpu": "128"
    nodeAllocatableResources:
      mapping:
        cpu:
          capacityKey: "cpu.example.com/cpu"
  - name: socket1cpus
    allowMultipleAllocations: true
    capacity:
      "cpu.example.com/cpu": "128"
    nodeAllocatableResources:
      mapping:
        cpu:
          capacityKey: "cpu.example.com/cpu"
          capacityMultiplier: 1

Приклад: прискорювач з допоміжними ресурсами (Накладні витрати)

Ось приклад ресурсного слайсу, де прискорювач потребує додаткових 8Gi памʼяті на кожен Pod для функціонування:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: my-node-xpus
spec:
  driver: xpu.example.com
  nodeName: my-node
  pool:
    name: xpu-pool
    generation: 1
    resourceSliceCount: 1
  devices:
  - name: xpu-model-x-001
    attributes:
      example.com/model:
        string: "model-x"
    nodeAllocatableResources:
      overhead:
        memory:
          perPod: "8Gi"

Після того як Pod було успішно привʼязано до вузла, точні кількості ресурсів вузла, доступних для виділення, виділених через DRA, агрегуються kube-scheduler і вбудовуються безпосередньо у поле status.nodeAllocatableResourceClaimStatuses Podʼа. Це забезпечує чітку, постійну передачу від планувальника до kubelet.

Ключовим моментом є те, що kubelet нативно споживає цей API для ідеального узгодження системних меж:

  • cgroups: cgroups Podʼа та контейнерів тепер включатимуть виділення на основі DRA, запобігаючи штучному обмеженню робочих навантажень ядром.
  • Оцінки OOM: kubelet враховує запити памʼяті DRA контейнера у його ефективному запиті памʼяті.

Ресурси вузла, доступні для виділення, є альфа-функцією і вмикаються, коли функціональну можливість DRANodeAllocatableResources увімкнено в kube-apiserver, kube-scheduler та kubelet.

Востаннє змінено August 30, 2026 at 10:31 AM PST: [uk] Ukrainian translation (all-in-one) (ac41b20ac1)