Це багатосторінкова версія цього розділу для друку. Натисніть тут, щоб надрукувати.

Повернутися до звичайного перегляду сторінки.

Керування ресурсами

Як Kubernetes представляє, запитує, виділяє та обмежує ресурси, які споживають робочі навантаження.

Цей розділ описує, як Kubernetes представляє, запитує, виділяє та обмежує ресурси, які споживають робочі навантаження, включно зі спеціалізованими апаратними пристроями.

1 - Resource managers

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

Менеджер топології

Це стабільна функція в Kubernetes, яка доступна починаючи з випуску 1.27. Ви більше не можете перемикати цю функцію (повʼязану функціональну можливість було вилучено).

Менеджер топології — це компонент kubelet, який координує набір компонентів, відповідальних за ці оптимізації. Щоб дізнатися більше, прочитайте Керування політиками топології на вузлі.

Менеджер CPU

Це стабільна функція в Kubernetes, яка доступна починаючи з випуску 1.26. Ви більше не можете перемикати цю функцію (повʼязану функціональну можливість було вилучено).

Менеджер CPU — це компонент kubelet, який забезпечує ексклюзивне виділення ресурсів для CPU. Він консультується з Менеджером топології для прийняття рішень щодо призначення ресурсів. Щоб дізнатися більше, прочитайте Керування політиками управління CPU на вузлі.

Політики призначення CPU подам

Після привʼязки Podʼа до вузла kubelet на цьому вузлі може потребувати або мультиплексування наявного апаратного забезпечення (наприклад, спільного використання CPU між кількома Podʼами), або виділення апаратного забезпечення шляхом резервування певних ресурсів (наприклад, виділення одного або кількох CPU для виключного використання одним Podʼом).

Зазвичай kubelet використовує CFS quota для забезпечення обмежень на використання CPU подами. Коли на вузлі працює багато подів, що завантажують CPU, робоче навантаження може переміщуватися між різними ядрами CPU залежно від того, чи обмежується под, і які ядра CPU доступні на момент планування. Багато робочих навантажень не чутливі до цього переміщення і тому працюють нормально без будь-якого втручання.

Однак у робочих навантаженнях, де спорідненість кешу CPU та затримка планування значно впливають на продуктивність, kubelet дозволяє використовувати альтернативні політики управління CPU для визначення деяких переваг розміщення на вузлі. Це реалізовано за допомогою Менеджера CPU та його політики. Існують дві доступні політики:

  • none: політика none явно включає наявну стандартну схему спорідненості CPU, не забезпечуючи спорідненості понад те, що автоматично робить планувальник ОС. Обмеження на використання CPU для подів Guaranteed та подів Burstable забезпечуються за допомогою CFS quota.
  • static: політика static дозволяє контейнерам у подах Guaranteed з цілими запитами CPU отримувати доступ до ексклюзивних CPU на вузлі. Ця ексклюзивність забезпечується за допомогою cpuset cgroup controller.

Примітка:

Системні служби, такі як середовище виконання контейнерів та сам kubelet, можуть і надалі працювати на цих виділених процесорах. Виключність поширюється лише на інші поди.

Менеджер CPU не підтримує відключення та підключення CPU під час виконання.

Політика static

Політика static дозволяє більш детально керувати CPU та забезпечує ексклюзивне призначення CPU. Ця політика керує спільним пулом CPU, який спочатку містить усі CPU на вузлі. Кількість CPU, доступних для ексклюзивного призначення, дорівнює загальній кількості CPU на вузлі за винятком будь-яких резервувань CPU, встановлених у конфігурації kubelet. CPU, зарезервовані цими параметрами, беруться цілими числами з початкового спільного пулу у порядку зростання за фізичним ідентифікатором ядра. Цей спільний пул є набором CPU, на яких працюють будь-які контейнери в подах BestEffort та Burstable. Контейнери в подах Guaranteed з дробовими запитами CPU також працюють на CPU зі спільного пулу. Лише контейнери, які є частиною пода Guaranteed і мають цілі запити CPU, отримують ексклюзивні CPU.

Примітка:

Kubelet вимагає резервування CPU більше за нуль, коли політика static увімкнена. Це тому, що нульове резервування CPU дозволило б спільному пулу стати порожнім.

Коли поди Guaranteed, контейнери яких відповідають вимогам для статичного призначення, плануються на вузлі, CPU видаляються зі спільного пулу та розміщуються в cpuset для контейнера. CFS quota не використовується для обмеження використання CPU цими контейнерами, оскільки їхнє використання обмежується самим доменом планування. Іншими словами, кількість CPU в cpuset контейнера дорівнює цілому числу CPU limit, зазначеному в специфікації пода. Це статичне призначення підвищує спорідненість CPU та зменшує перемикання контексту через обмеження для навантаження, що залежить від CPU.

Розглянемо контейнери в наступних специфікаціях пода:

spec:
  containers:
  - name: nginx
    image: nginx

Под вище працює в класі QoS BestEffort, оскільки не вказано жодних ресурсних requests або limits. Він працює в спільному пулі.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
      requests:
        memory: "100Mi"

Под вище працює в класі QoS Burstable, оскільки ресурсні requests не дорівнюють limits, а кількість cpu не вказана. Він працює в спільному пулі.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
      requests:
        memory: "100Mi"
        cpu: "1"

Под вище працює в класі QoS Burstable, оскільки ресурсні requests не дорівнюють limits. Він працює в спільному пулі.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"
      requests:
        memory: "200Mi"
        cpu: "2"

Под вище працює в класі QoS Guaranteed, оскільки requests дорівнюють limits. І обмеження ресурсу CPU для контейнера є цілим числом, більшим або рівним одиниці. Контейнер nginx отримує 2 ексклюзивні CPU.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "1.5"
      requests:
        memory: "200Mi"
        cpu: "1.5"

Под вище працює в класі QoS Guaranteed, оскільки requests дорівнюють limits. Але обмеження ресурсу CPU для контейнера є дробовим числом. Він працює в спільному пулі.

spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      limits:
        memory: "200Mi"
        cpu: "2"

Под вище працює в класі QoS Guaranteed, оскільки вказано лише limits, а requests прирівнюються до limits, коли їх не вказано явно. І обмеження ресурсу CPU для контейнера є цілим числом, більшим або рівним одиниці. Контейнер nginx отримує 2 ексклюзивні CPU.

Параметри політики Static

Ось доступні параметри політики static управління CPU, перераховані в алфавітному порядку:

align-by-socket (alpha, зазвичай приховано)
Вирівнювання CPU за фізичним пакетом / сокетом, а не за логічними межами NUMA (доступно з Kubernetes v1.25)
distribute-cpus-across-cores (alpha, зазвичай приховано)
Розподіл віртуальних ядер, іноді званих апаратними потоками, по різних фізичних ядрах (доступно з Kubernetes v1.31)
distribute-cpus-across-numa (beta, зазвичай видно)
Розподіл CPU по різних доменах NUMA, з метою досягнення рівномірного балансу між обраними доменами (доступно з Kubernetes v1.23)
full-pcpus-only (GA, зазвичай видно)
Завжди виділяти повні фізичні ядра (доступно з Kubernetes v1.22, GA з Kubernetes v1.33)
strict-cpu-reservation (GA, зазвичай видно)
Запобігання запуску всіх подів незалежно від їх класу якості обслуговування на зарезервованих CPU (доступно з Kubernetes v1.32, GA з Kubernetes v1.35)
prefer-align-cpus-by-uncorecache (GA, зазвичай видно)
Вирівнювання CPU за межами кешу uncore (Last-Level) на основі найкращих зусиль (доступно з Kubernetes v1.32)

Ви можете вмикати або вимикати групи параметрів залежно від їх рівня зрілості, використовуючи наступні функціональні ворота:

  • CPUManagerPolicyBetaOptions (стандартно увімкнено). Вимкніть, щоб приховати параметри рівня beta.
  • CPUManagerPolicyAlphaOptions (стандартно вимкнено). Увімкніть, щоб показати параметри рівня alpha.

Вам все одно доведеться увімкнути кожен параметр, використовуючи поле cpuManagerPolicyOptions у файлі конфігурації kubelet.

Щоб дізнатися більше про окремі параметри, які можна налаштувати, читайте далі.

full-pcpus-only

Якщо вказано параметр full-pcpus-only політики, політика static завжди виділятиме повні фізичні ядра. Зазвичай, без цього параметра, політика static виділяє CPU, використовуючи топологічно-орієнтоване найкраще підходяще розміщення. На системах з увімкненим SMT політика може виділяти окремі віртуальні ядра, які відповідають апаратним потокам. Це може призвести до того, що різні контейнери будуть використовувати одні й ті ж фізичні ядра; така поведінка, у свою чергу, сприяє проблемі шумних сусідів. З увімкненим параметром, под буде прийнято kubelet лише в тому випадку, якщо запит CPU всіх його контейнерів може бути виконаний шляхом виділення повних фізичних ядер. Якщо под не отримує допуск, він буде переведений у стан Failed з повідомленням SMTAlignmentError.

distribute-cpus-across-numa

Якщо вказано параметр distribute-cpus-across-numa, політика static рівномірно розподіляє CPU між NUMA-вузлами у випадках, коли для задоволення виділення потрібно більше одного NUMA-вузла. Стандартно, CPUManager розміщує CPU на одному NUMA-вузлі, поки він не заповниться, а залишкові CPU просто переходять до наступного NUMA-вузла. Це може спричинити небажані вузькі місця в паралельному коді, що використовує барʼєри (та подібні примітиви синхронізації), оскільки такий код зазвичай працює лише так швидко, як його найповільніший працівник (який сповільнюється через те, що на принаймні одному NUMA-вузлі доступно менше CPU). Розподіляючи CPU рівномірно між NUMA-вузлами, розробники застосунків можуть легше забезпечити, щоб жоден працівник не страждав від ефектів NUMA більше, ніж інші, покращуючи загальну продуктивність таких застосунків.

align-by-socket

Якщо вказано параметр align-by-socket, CPU будуть вважатися вирівняними на межі сокета при прийнятті рішення про виділення CPU контейнеру. Стандартно, CPUManager вирівнює виділення CPU на межі NUMA, що може призвести до зниження продуктивності, якщо для задоволення виділення потрібно більше одного NUMA-вузла. Хоча він намагається забезпечити виділення всіх CPU з мінімальної кількості NUMA-вузлів, немає гарантії, що ці NUMA-вузли будуть на одному сокеті. Направляючи CPUManager явно вирівнювати CPU на межі сокета замість межі NUMA, ми можемо уникнути таких проблем. Зверніть увагу, що цей параметр політики не сумісний з політикою single-numa-node TopologyManager і не застосовується до апаратного забезпечення, де кількість сокетів перевищує кількість NUMA-вузлів.

distribute-cpus-across-cores

Якщо вказано параметр distribute-cpus-across-cores, політика static намагатиметься виділяти віртуальні ядра (апаратні потоки) на різних фізичних ядрах. Стандартно, CPUManager намагається розміщувати CPU на якомога меншій кількості фізичних ядер, що може призвести до конкуренції між CPU на одному фізичному ядрі та спричинити вузькі місця у продуктивності. Увімкнувши параметр distribute-cpus-across-cores, політика static забезпечує розподіл CPU на якомога більшій кількості фізичних ядер, зменшуючи конкуренцію на одному фізичному ядрі та покращуючи загальну продуктивність. Однак важливо зазначити, що ця стратегія може бути менш ефективною при високому навантаженні системи. У таких умовах користь від зменшення конкуренції зменшується. Навпаки, стандартна поведінка може допомогти зменшити накладні витрати на міжядерну комунікацію, потенційно забезпечуючи кращу продуктивність при високому навантаженні.

strict-cpu-reservation

Параметр reservedSystemCPUs у KubeletConfiguration, або застаріла опція командного рядка kubelet --reserved-cpus, визначає явний набір CPU для системних демонів ОС та демонів Kubernetes. Більше деталей про цей параметр можна знайти на сторінці Явно зарезервований список CPU. Стандартно, ця ізоляція реалізується лише для гарантованих подів з цілими запитами CPU, а не для подів з можливістю перевантаження та подів з найкращим зусиллям (та гарантованих подів з дробовими запитами CPU). Допуск здійснюється лише шляхом порівняння запитів CPU з доступними CPU. Оскільки ліміт CPU вищий за запит, стандартна поведінка дозволяє подам з можливістю перевантаження та подам з найкращим зусиллям використовувати всю ємність reservedSystemCPUs і спричиняти нестачу ресурсів для служб ОС у реальних розгортаннях. Якщо параметр політики strict-cpu-reservation увімкнено, політика static не дозволить жодному робочому навантаженню використовувати ядра CPU, зазначені в reservedSystemCPUs.

prefer-align-cpus-by-uncorecache

Якщо вказано параметр prefer-align-cpus-by-uncorecache, політика static виділятиме ресурси CPU для окремих контейнерів таким чином, щоб усі CPU, призначені контейнеру, використовували один і той же блок кешу uncore (також відомий як кеш останнього рівня або LLC). Зазвичай CPUManager щільно розподіляє призначення CPU, що може призвести до того, що контейнери отримують CPU з кількох кешів uncore. Ця опція дозволяє CPUManager виділяти CPU таким чином, щоб максимально ефективно використовувати кеш uncore. Виділення здійснюється на основі найкращих зусиль, намагаючись призначити якомога більше CPU в межах одного кешу uncore. Якщо вимога контейнера щодо CPU перевищує ємність одного кешу uncore, CPUManager мінімізує кількість використаних кешів uncore, щоб підтримувати оптимальне вирівнювання кешу uncore. Конкретні робочі навантаження можуть отримати вигоду у продуктивності від зменшення затримки між кешами та шумних сусідів на рівні кешу. Якщо CPUManager не може оптимально вирівняти CPU при наявності достатніх ресурсів на вузлі, контейнер все одно буде прийнято з використанням стандартного щільного розподілу.

Менеджер памʼяті

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

Це стабільна функція в , яка загальнодоступна починаючи з версії 1.32. Вперше вона зʼявилась у випуску v1.21.

Memory Manager є компонентом kubelet, який забезпечує ексклюзивне виділення ресурсів памʼяті. Він консультується з Topology Manager для прийняття рішень щодо призначення ресурсів. Щоб дізнатися більше, прочитайте Керування політиками управління памʼяттю на вузлі.

Політики призначення памʼяті для подів

В Kubernetes Memory Manager виділяє ресурси оперативної памʼяті (RAM, а також за потреби великі сторінки Linux) для подів у QoS class Guaranteed .

Memory Manager використовує протокол генерації підказок для визначення найбільш підходящої NUMA-спорідненості для пода. Memory Manager передає ці підказки центральному менеджеру (Topology Manager). На основі як підказок, так і політики Topology Manager, под приймається або відхиляється на вузлі.

Більше того, Memory Manager забезпечує, щоб памʼять, яку запитує под, виділялася з мінімальної кількості NUMA-вузлів.

Щоб дізнатися більше, прочитайте Керування політиками управління памʼяттю на вузлі.

Менеджер пристроїв

Стан функціоналу: Stable починаючи з Kubernetes v1.26

Device Manager є компонентом kubelet, який виділяє апаратні пристрої для подів за допомогою API втулків пристроїв. Він консультується з Topology Manager, використовуючи інформацію про топологію, надану втулками пристроїв, для прийняття рішень щодо призначення ресурсів. Щоб дізнатися більше, прочитайте Інтеграція втулків пристроїв з Topology Manager.

Менеджери ресурсів на рівні Podʼів

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

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

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

Підтримка ресурсів на рівні Podʼів для менеджерів ресурсів kubelet (Topology, CPU та Memory) дозволяє менеджерам ресурсів використовувати .spec.resources безпосередньо для рішень щодо вирівнювання за NUMA та ексклюзивного виділення.

Щоб дізнатися більше, перегляньте присвячену сторінку концепції Менеджери ресурсів на рівні Podʼів або прочитайте, як надавати ресурси CPU та памʼяті на рівні Podʼів.

Що далі

2 - Динамічне виділення ресурсів

Стан функціоналу: Stable починаючи з Kubernetes v1.35
Докладніше про цей функціонал

Це стабільна функція в Kubernetes, яка загальнодоступна починаючи з версії v1.35. Вперше вона зʼявилась у випуску v1.30. Ви більше не можете вимкнути або відмовитися від цієї функції чи поведінки (це заблоковано); якщо ви явно встановите значення для повʼязаної функціональної можливості DynamicResourceAllocation, Kubernetes проігнорує це, але не повідомить про помилку.

Цей розділ знайомить з динамічним виділенням ресурсів (Dynamic Resource Allocation, DRA) у Kubernetes.

DRA — функція Kubernetes, яка дозволяє вам запитувати ресурси та ділитися ними з іншими Podʼами. Ці ресурси часто приєднуються до пристроїв, наприклад, до апаратних прискорювачів.

З DRA драйвери пристроїв і адміністратори кластерів визначають класи пристроїв, які доступні для заявки в робочих навантаженнях. Kubernetes виділяє відповідні пристрої для конкретних заявок і розміщує відповідні Podʼи на вузлах, які можуть отримати доступ до виділених пристроїв.

Виділення ресурсів за допомогою DRA схоже на динамічне надання томів, в якому ви використовуєте PersistentVolumeClaims, щоб запитати ємність сховища від класів сховища і запитувати заявлену ємність для використання у ваших Podʼах.

Переваги DRA

DRA надає гнучкий спосіб категоризації, запиту та використання пристроїв у вашому кластері. Використання DRA має такі переваги:

  • Гнучке фільтрування пристроїв: використовуйте загальну мову виразів (CEL) для виконання детального фільтрування за конкретними атрибутами пристроїв.
  • Спільне використання пристроїв: діліться одним і тим же ресурсом між кількома контейнерами або Podʼами, посилаючись на відповідну заявку на ресурс.
  • Конфігурація пристроїв: прикріплюйте специфічні для постачальника конфігурації пристроїв до вашої заявки на ресурс, що дозволяє конфігурувати пристрої для кожного робочого навантаження окремо, а не для кожного вузла, як це відбувається сьогодні.
  • Централізована категоризація пристроїв: драйвери пристроїв і адміністратори кластерів можуть використовувати класи пристроїв, щоб надати операторам застосунків категорії апаратного забезпечення, які оптимізовані для різних випадків використання. Наприклад, ви можете створити клас пристроїв, оптимізований за вартістю для загальних робочих навантажень, і клас пристроїв високої продуктивності для критичних завдань.
  • Спрощені запити Podʼів: за допомогою DRA операторам застосунків не потрібно вказувати кількість пристроїв у запитах ресурсів Podʼа. Замість цього Pod посилається на заявку на ресурс, а конфігурація пристроїв у цій заявці застосовується до Podʼа.

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

Типи користувачів DRA

Процес використання DRA для виділення пристроїв включає такі типи користувачів:

  • Власник пристрою: відповідає за пристрої. Власники пристроїв можуть бути комерційними постачальниками, оператором кластера або іншою сутністю. Щоб використовувати DRA, пристрої повинні мати драйвери, сумісні з DRA, які виконують такі дії:

    • Створюють ResourceSlices, які надають Kubernetes інформацію про вузли та ресурси.
    • Оновлюють ResourceSlices, коли змінюється ємність ресурсів у кластері.
    • Налаштовують пристрої відповідно до заявки та приєднують їх до контейнерів через Container Device Interface (CDI).
    • За бажанням створюють DeviceClasses, які оператори робочих навантажень можуть використовувати для заявки на пристрої.
  • Адміністратор кластера: відповідає за налаштування кластерів і вузлів, підключення пристроїв, установку драйверів та подібні завдання. Щоб використовувати DRA, адміністратори кластерів виконують такі дії:

    • Підключають пристрої до вузлів.
    • Встановлюють драйвери пристроїв, які підтримують DRA.
    • За бажанням створюють DeviceClasses, які оператори робочих навантажень можуть використовувати для заявки на пристрої.
  • Оператор робочих навантажень: відповідає за розгортання та управління робочими навантаженнями в кластері. Щоб використовувати DRA для виділення пристроїв для Podʼів, оператори робочих навантажень виконують такі дії:

    • Створюють ResourceClaims або ResourceClaimTemplates, щоб запитати конкретні конфігурації в межах DeviceClasses.
    • Розгортають робочі навантаження, які використовують конкретні ResourceClaims або ResourceClaimTemplates.

Обмеження

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

Що далі

2.1 - Обʼєкти API DRA

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

Термінологія DRA

DRA використовує такі види API Kubernetes для забезпечення основної функціональності виділення ресурсів. Усі ці види API включені вгрупу API resource.k8s.io/v1 .

DeviceClass
Визначає категорію пристроїв, які можуть бути запитані, і те, як вибрати конкретні атрибути пристроїв у заявках. Параметри DeviceClass можуть дорівнювати нулю або більше пристроїв у ResourceSlices. Щоб запитувати пристрої з DeviceClass, ResourceClaims вибирають певні атрибути пристрою.
ResourceClaim
Описує запити на доступ до приєднаних ресурсів, таких як пристрої, у кластері. Вимоги до ресурсу надають Podʼам доступ до певного ресурсу. ResourceClaims можуть створюватися операторами робочого навантаження або генеруватися Kubernetes на основі шаблону ResourceClaimTemplate.
ResourceClaimTemplate
Визначає шаблон, який Kubernetes використовує для створення запитів на ресурси (ResourceClaims) для робочого навантаження. Шаблони ResourceClaimTemplates надають Podʼам доступ до окремих схожих ресурсів. Кожний запит ресурсу, який Kubernetes генерує на основі шаблону, привʼязується до певного Podʼа. Коли Pod завершує роботу, Kubernetes видаляє відповідну заявку на ресурс.
ResourceSlice
Представляє собою один або декілька ресурсів, приєднаних до вузлів, таких як пристрої. Драйвери створюють розділи ресурсу і керують ними у кластері. Коли ResourceClaim створюється і використовується у Podʼі, Kubernetes використовує ResourceSlices для пошуку вузлів, які мають доступ до заявлених ресурсів. Kubernetes виділяє ресурси для ResourceClaim і планує роботу Podʼа на вузлі, який може отримати доступ до ресурсів.

DeviceClass

DeviceClass дозволяє адміністраторам кластера або драйверам пристроїв визначати категорії пристроїв у кластері. Класи пристроїв вказують операторам, які пристрої вони можуть запитувати і як вони можуть запитувати ці пристрої. Ви можете використовувати загальну мову виразів (CEL) для вибору пристроїв на основі певних атрибутів. ResourceClaim, яка посилається на DeviceClass, може потім запитувати певні конфігурації в межах DeviceClass.

Щоб створити DeviceClass, див. Налаштування DRA у кластері.

ResourceClaims та ResourceClaimTemplates

ResourceClaim визначає ресурси, які потрібні робочому навантаженню. Кожен ResourceClaim має запити (requests), які посилаються на DeviceClass і вибирають пристрої з цього DeviceClass. ResourceClaims також можуть використовувати селектори (selectors) для фільтрації пристроїв, які відповідають певним вимогам, і можуть використовувати обмеження (constraints) для обмеження пристроїв, які можуть задовольнити запит. ResourceClaims можуть створюватися операторами робочого навантаження або генеруватися Kubernetes на основі шаблону ResourceClaimTemplate. Шаблон ResourceClaimTemplate визначає шаблон, який Kubernetes може використовувати для автоматичного створення ResourceClaims для Podʼів.

Використання ResourceClaims та ResourceClaimTemplates

Метод, який ви використовуєте, залежить від ваших вимог, як показано нижче:

  • ResourceClaim: ви хочете, щоб кілька Podʼів мали спільний доступ до певних пристроїв. Ви вручну керуєте життєвим циклом ResourceClaims, які створюєте.
  • ResourceClaimTemplate: ви хочете, щоб Podʼи мали незалежний доступ до окремих, схожих за конфігурацією пристроїв. Kubernetes генерує ResourceClaims з специфікації в ResourceClaimTemplate. Тривалість кожного згенерованого ResourceClaim привʼязується до тривалості існування відповідного Podʼа.
  • PodGroup ResourceClaimTemplate: ви хочете, щоб PodGroups мали незалежний доступ до окремих, схожих за конфігурацією пристроїв, які можуть бути спільно використані їхніми Podʼами. Kubernetes генерує один ResourceClaim для PodGroup з специфікації в ResourceClaimTemplate. Тривалість кожного згенерованого ResourceClaim привʼязується до тривалості існування відповідного PodGroup. Це вимагає, щоб функція DRAWorkloadResourceClaims була увімкнена.

Коли ви визначаєте робоче навантаження, ви можете використовувати Загальну мову виразів (CEL) для фільтрації за конкретними атрибутами пристроїв або ємністю. Доступні параметри для фільтрації залежать від пристрою та драйверів.

Якщо ви безпосередньо посилаєтеся на конкретний ResourceClaim у Pod, цей ResourceClaim повинен вже існувати в тому ж просторі імен, що й Pod. Якщо ResourceClaim не існує в просторі імен, Pod не буде заплановано. Ця поведінка подібна до того, як PersistentVolumeClaim повинен існувати в тому ж просторі імен, що й Pod, який посилається на нього.

Ви можете посилатися на автоматично згенерований ResourceClaim у Podʼі, але це не рекомендується, оскільки автоматично згенеровані ResourceClaims привʼязані до тривалості існування Podʼа або PodGroup, який викликав генерацію.

Щоб дізнатися, як запитувати ресурси за допомогою одного з цих методів, див. Виділення пристроїв для робочих навантажень з DRA.

Список пріоритетів

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

Це стабільна функція в , яка загальнодоступна починаючи з версії 1.36. Вперше вона зʼявилась у випуску v1.33.

Ви можете надати список пріоритетів підзапитів для запитів у ResourceClaim або ResourceClaimTemplate. Планувальник вибере перший підзапит, який можна виконати. Це дозволяє користувачам вказувати альтернативні пристрої, які можуть бути використані робочим навантаженням, якщо первинний вибір недоступний.

У наведеному нижче прикладі ResourceClaimTemplate запитує пристрій з кольором чорний і розміром великий. Якщо пристрій з цими атрибутами недоступний, Pod не може бути заплановано. Завдяки функції списку пріоритетів можна вказати другий варіант, який запитує два пристрої з кольором білий і розміром малий. Великий чорний пристрій буде наданий, якщо він доступний. Якщо ні, але два маленькі білі пристрої доступні, Pod все ще зможе працювати.

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: prioritized-list-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        firstAvailable:
        - name: large-black
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "black" &&
                device.attributes["resource-driver.example.com"].size == "large"
        - name: small-white
          deviceClassName: resource.example.com
          selectors:
          - cel:
              expression: |-
                device.attributes["resource-driver.example.com"].color == "white" &&
                device.attributes["resource-driver.example.com"].size == "small"
          count: 2

Якщо под відповідає вимогам для декількох вузлів у кластері, планувальник використовуватиме індекс обраних субзапитів із будь-яких пріоритетних списків як один із вхідних параметрів під час оцінки кожного вузла. Отже, вузли, які можуть виділити пристрої, запитувані в субзапиті з вищим рейтингом, мають більшу ймовірність бути обраними, ніж вузли, які можуть виділити пристрої лише для субзапитів з нижчим рейтингом.

Рішення приймається для кожного Podʼа окремо, тому якщо Pod є членом ReplicaSet або подібної групи, ви не можете розраховувати на те, що всі члени групи матимуть однаковий субзапит. Ваше навантаження повинно бути здатним пристосуватися до цього.

Workload ResourceClaims

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

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

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

Коли ви організовуєте Podʼи за допомогою Workload API, ви можете резервувати ResourceClaims для цілих PodGroups замість окремих Podʼів і генерувати ResourceClaimTemplates для PodGroup замість одного Podʼа, що дозволяє Podʼам у PodGroup спільно використовувати доступ до пристроїв, виділених для згенерованого ResourceClaim.

Ця функція вирішує дві проблеми:

  • Список status.reservedFor API ResourceClaim може містити лише 256 елементів. Оскільки kube-scheduler записує в цей список лише окремі Podʼи, лише 256 Podʼів можуть спільно використовувати один ResourceClaim. Завдяки можливості запису PodGroups у status.reservedFor, ResourceClaim можуть спільно використовувати значно більше ніж 256 Podʼів.
  • Podʼи можуть спільно використовувати ResourceClaim лише тоді, коли відома його точна назва. Для складних робочих навантажень, що реплікують групи Podʼів, ResourceClaims, якими спільно користуються Podʼи в кожній групі, потрібно створювати та видаляти явно, коли набір груп масштабується вгору та вниз. Генеруючи ResourceClaims для кожної PodGroup, один ResourceClaimTemplate може стати основою для ResourceClaims, які автоматично реплікуються та можуть спільно використовуватися Podʼами у PodGroup.

API PodGroup визначає поле spec.resourceClaims з такою самою структурою та подібним значенням, як і поле spec.resourceClaims в API Pod:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-group
  namespace: some-ns
spec:
  ...
  resourceClaims:
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template

Як і заявки, зроблені Podʼами, заявки для PodGroup, що визначають resourceClaimName, посилаються на ResourceClaim за іменем. Заявки, що визначають resourceClaimTemplateName, посилаються на ResourceClaimTemplate, який реплікується в один ResourceClaim для всієї PodGroup, який може бути спільно використаний її Podʼами.

Коли Pod визначає заявку з name, resourceClaimName та resourceClaimTemplateName, які всі збігаються з однією з spec.resourceClaims його PodGroup, kube-scheduler резервує ResourceClaim для PodGroup замість Podʼа. Якщо заявка Podʼа не збігається з жодною заявкою його PodGroup, kube-scheduler резервує ResourceClaim для Podʼа. У будь-якому випадку резервування записується в status.reservedFor ResourceClaim. Резервування PodGroup та відповідне виділення ресурсів зберігаються в ResourceClaim до видалення PodGroup, навіть якщо група більше не має Podʼа.

Коли заявка Podʼа, що збігається з заявкою PodGroup, визначає resourceClaimTemplateName, тоді для PodGroup генерується один ResourceClaim. Інші Podʼи в групі, які визначають ту ж саму заявку, будуть використовувати цей згенерований ResourceClaim замість того, щоб створювати новий ResourceClaim для кожного Podʼа. Незалежно від того, чи збігається заявка resourceClaimTemplateName з заявкою PodGroup, імʼя згенерованого ResourceClaim записується в status.resourceClaimStatuses Podʼа.

Заявка PodGroup, що збігається з ResourceClaimTemplate, спонукає до створення ResourceClaim лише тоді, коли увімкнено функцію DRAWorkloadResourceClaims. Замість створення окремих ResourceClaims для кожного Podʼа, коли функцію вимкнено, жоден ResourceClaim не створюється, щоб запобігти створенню помилкових окремих ResourceClaims під час оновлень кластера або розгортань/відкатів функції між kube-apiserver та kube-controller-manager.

ResourceClaims, згенеровані з ResourceClaimTemplate для PodGroup, слідують життєвому циклу PodGroup. ResourceClaim створюється, коли існують як PodGroup, так і його ResourceClaimTemplate. ResourceClaim видаляється після видалення PodGroup і коли ResourceClaim більше не зарезервований.

Розглянемо наступний приклад:

apiVersion: scheduling.k8s.io/v1beta1
kind: PodGroup
metadata:
  name: training-group
  namespace: some-ns
spec:
  ...
  resourceClaims:
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template
---
apiVersion: v1
kind: Pod
metadata:
  name: training-group-pod-1
  namespace: some-ns
spec:
  ...
  schedulingGroup:
    podGroupName: training-group
  resourceClaims:
  - name: pod-claim
    resourceClaimName: my-pod-claim
  - name: pod-claim-template
    resourceClaimTemplateName: my-pod-template
  - name: pg-claim
    resourceClaimName: my-pg-claim
  - name: pg-claim-template
    resourceClaimTemplateName: my-pg-template

У цьому прикладі PodGroup training-group має один Pod на імʼя training-group-pod-1. Заявки Podʼа pod-claim та pod-claim-template не збігаються з жодною заявкою PodGroup, тому ці заявки не впливають на PodGroup: ResourceClaim my-pod-claim стає зарезервованим для Podʼа, а ResourceClaim, згенерований з ResourceClaimTemplate my-pod-template, також стає зарезервованим для Podʼа. Заявки pg-claim та pg-claim-template збігаються з заявками PodGroup. ResourceClaim my-pg-claim стає зарезервованим для PodGroup, а ResourceClaim, згенерований з ResourceClaimTemplate my-pg-template, також стає зарезервованим для PodGroup.

Повʼязування ResourceClaims з ресурсами Workload API контролюється функціональною можливістю DRAWorkloadResourceClaims у kube-apiserver, kube-controller-manager, kube-scheduler та kubelet.

ResourceSlice

Кожен ResourceSlice представляє один або декілька пристроїв у пулі. Пулом керує драйвер пристрою, який створює та керує ResourceSlices. Ресурси у пулі можуть бути представлені одним ResourceSlice або охоплювати декілька ResourceSlice.

ResourceSlices надають корисну інформацію користувачам пристроїв і планувальнику, а також мають вирішальне значення для динамічного розподілу ресурсів. Кожен ResourceSlice повинен містити наступну інформацію:

  • Resource pool: група з одного або декількох ресурсів, якими керує драйвер. Пул може охоплювати більше ніж один ResourceSlice. Зміни в ресурсах пулу повинні бути поширені на всі ResourceSlices у цьому пулі. Драйвер пристрою, який керує пулом, відповідає за забезпечення цього.
  • Devices: пристрої в керованому пулі. ResourceSlice може перераховувати кожен пристрій у пулі або підмножину пристроїв у пулі. ResourceSlice визначає інформацію про пристрій, таку як атрибути, версії та ємність. Користувачі пристроїв можуть вибирати пристрої для виділення, фільтруючи за інформацією про пристрої в ResourceClaims або в DeviceClasses.
  • Nodes: вузли, які можуть отримувати доступ до ресурсів. Драйвери можуть вибирати, які вузли можуть отримувати доступ до ресурсів, чи це всі вузли в кластері, один названий вузол або вузли, які мають специфічні мітки вузлів.

Драйвери використовують контролер для узгодження ResourceSlices у кластері з інформацією, яку має опублікувати драйвер. Цей контролер перезаписує будь-які ручні зміни, такі як створення або модифікація ResourceSlices користувачами кластера.

Розгляньте наступний приклад ResourceSlice:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: cat-slice
spec:
  driver: "resource-driver.example.com"
  pool:
    generation: 1
    name: "black-cat-pool"
    resourceSliceCount: 1
  # Поле allNodes визначає, чи може будь-який вузол кластера отримати доступ до пристрою.
  allNodes: true
  devices:
  - name: "large-black-cat"
    attributes:
      color:
        string: "black"
      size:
        string: "large"
      cat:
        bool: true

Цим ResourceSlice керує драйвер resource-driver.example.com у пулі black-cat-pool. Поле allNodes: true вказує на те, що будь-який вузол кластера може отримати доступ до пристроїв. У ResourceSlice є один пристрій на імʼя large-black-cat з наступними атрибутами:

  • color: black
  • size: large
  • cat: true

DeviceClass може вибрати цей ResourceSlice за допомогою цих атрибутів, а ResourceClaim може відфільтрувати певні пристрої у цьому DeviceClass.

Іменування та пріоритизація

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

Це дозволяє впливати на пріоритет розподілу ресурсів за допомогою імен, призначених пулам та ResourceSlices. Зверніть увагу, що пули без умов привʼязки завжди оцінюються перед тими, що мають умови привʼязки, незалежно від їхніх імен.

Для драйверів, створених за допомогою пакунка Go k8s.io/dynamic-resources/kubeletplugin або контролера ResourceSlice з цього модуля, ці компоненти автоматично обробляють назви ResourceSlice, щоб забезпечити їх оцінку в порядку, визначеному драйвером.

Адміністративний доступ

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

Це стабільна функція в , яка загальнодоступна починаючи з версії 1.36. Вперше вона зʼявилась у випуску v1.32.

Ви можете позначити запит у ResourceClaim або ResourceClaimTemplate як такий, що має привілейовані можливості для завдань обслуговування та усунення несправностей. Запит з правами адміністратора надає доступ до пристроїв, які використовуються, і може увімкнути додаткові дозволи, якщо зробити пристрій доступним у контейнері:

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: large-black-cat-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        exactly:
          deviceClassName: resource.example.com
          allocationMode: All
          adminAccess: true

Доступ адміністратора є привілейованим режимом, і його не слід надавати звичайним користувачам у кластерах з багатокористувацькою архітектурою. Поле adminAccess можуть використовувати лише ті користувачі, які мають дозвіл на створення обʼєктів ResourceClaim або ResourceClaimTemplate у просторах імен, позначених тегом resource.kubernetes.io/admin-access: "true" (з урахуванням регістру). Це гарантує, що користувачі, які не є адміністраторами, не зможуть зловживати цією функцією.

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

Атрибути типу список

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

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

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

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

Для авторів ResourceClaim (кінцевих користувачів) це означає, що matchAttribute та distinctAttribute працюють краще для цих випадків.

  • matchAttribute — два атрибути повинні мати непорожній перетин списків, а не бути ідентичними (скалярні значення розглядаються як списки з одним елементом). Це означає, що якщо один драйвер публікує одне значення, наприклад, для кореня PCIe, а інший драйвер публікує список, обмеження виконується, якщо одне значення зʼявляється десь у списку.
  • distinctAttribute — значення атрибутів повинні бути попарно незʼєднаними (жодне значення не є спільним між будь-якими двома пристроями)

Щоб допомогти авторам ResourceClaim використовувати атрибути, які можуть бути списками, у виразах CEL, ця функція також запроваджує функцію CEL includes().

# Scalar attribute (backward compatible)
# assume: device.attributes["dra.example.com"].model = "model-a"
device.attributes["dra.example.com"].model.includes("model-a")  # true
device.attributes["dra.example.com"].model.includes("model-b")  # false

# List-type attribute (requires DRAListTypeAttributes)
# assume: device.attributes["dra.example.com"].supported-models= ["model-a", "model-b"]
device.attributes["dra.example.com"].supported-models.includes("model-a")  # true
device.attributes["dra.example.com"].supported-models.includes("model-c")  # false

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

Зазвичай кожен DeviceAttribute містить точно одне скалярне значення: булеве, ціле число, рядок або рядок семантичної версії. Функція DRAListTypeAttributes розширює DeviceAttribute чотирма полями типу список, дозволяючи пристрою рекламувати кілька значень для одного атрибута:

  • bools — список булевих значень
  • ints — список 64-бітних цілих чисел
  • strings — список рядків (кожен не більше 64 символів)
  • versions — список рядків семантичних версій відповідно до специфікації semver.org 2.0.0 (кожен не більше 64 символів)

Загальна кількість окремих значень атрибутів на пристрій (скалярні поля плюс всі елементи списків разом) обмежена 48. Коли будь-який пристрій у ResourceSlice використовує цю функцію або інші розширені функції, такі як taints, ResourceSlice буде обмежений максимум 64 пристроями. Використовуйте атрибути типу список або інші розширені функції, такі як taints.

Ось приклад пристрою, який оголошує кілька підтримуваних моделей за допомогою атрибута рядка типу список:

kind: ResourceSlice
apiVersion: resource.k8s.io/v1
metadata:
  name: example-resourceslice
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 1
  driver: dra.example.com
  devices:
  - name: gpu-0
    attributes:
      dra.example.com/supported-models:
        strings:
        - model-a
        - model-b

Атрибути типу список контролюються функціональною можливістю DRAListTypeAttributes у kube-apiserver та kube-scheduler.

Похідні атрибути

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

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

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

Обмеження matchAttribute та distinctAttribute зазвичай вимагають, щоб пристрої публікували атрибути під точно такою ж назвою. Якщо драйвер GPU публікує pcie_locality, а драйвер NIC публікує pcie_root (або вбудовує ту саму інформацію в рядок на зразок numa0-pcie1), планувальник не має способу розпізнати, що вони представляють одне й те саме, тому пристрої від двох драйверів не можуть бути розміщені разом без попередньої домовленості про спільну назву атрибута.

derivedAttributes дозволяє вам подолати цю прогалину безпосередньо, не чекаючи, поки драйвери стандартизують спільні назви атрибутів. Додайте один або кілька записів derivedAttributes до запиту, у .spec.devices.requests[].exactly або .spec.devices.requests[].firstAvailable[]. Кожен запис визначає вираз CEL, який планувальник обчислює для кожного кандидата пристрою для цього запиту. Результат стає віртуальним атрибутом, на який можна посилатися з обмеження matchAttribute або distinctAttribute точно так само, як на атрибут пристрою, наданий драйвером.

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: gpu-nic-numa-alignment
spec:
  devices:
    requests:
    - name: gpu
      exactly:
        deviceClassName: gpu.example.com
        count: 1
        derivedAttributes:
        - name: derived/numa
          expression: device.attributes["gpu.example.com"].numa
    - name: nic
      exactly:
        deviceClassName: nic.example.com
        count: 1
        derivedAttributes:
        - name: derived/numa
          expression: device.attributes["nic.example.com"].numaNode
    constraints:
    - requests: ["gpu", "nic"]
      matchAttribute: derived/numa

У цьому прикладі драйвери gpu та nic публікують інформацію про топологію під різними назвами атрибутів (numa та numaNode). Кожен запит обчислює спільне значення derived/numa з атрибутів власного пристрою, а обмеження matchAttribute вирівнює два запити за цим віртуальним атрибутом, навіть якщо базові драйвери ніколи не домовлялися про спільну назву атрибута.

Кілька речей, які варто знати про derivedAttributes:

  • Іменування: name має бути DNS-піддоменом, за яким слідує / та C-ідентифікатор, у тому ж форматі, що використовується для назв атрибутів, наданих драйвером (наприклад, example.com/numaNode або derived/numaNode). Якщо назва збігається з атрибутом, вже опублікованим драйвером, значення похідного атрибута затінює надане драйвером для зіставлення обмежень. Використовуйте префікс домену, який жоден драйвер не використовуватиме, наприклад derived/, якщо ви хочете уникнути ненавмисного затінення. Ви можете визначити до 32 похідних атрибутів на запит.
  • Повинен використовуватися обмеженням: кожен похідний атрибут повинен бути згаданий принаймні в одному обмеженні matchAttribute або distinctAttribute, яке застосовується до запиту (або підзапиту), що його визначає. Інакше ResourceClaim не пройде перевірку.
  • Область та порядок обчислення: expression обчислюється один раз для кожного кандидата пристрою, після того як власні селектори CEL запиту (.selectors[].cel) вже відфільтрували цей пристрій. Як результат, похідні атрибути не можуть бути використані у виразах селекторів і не доступні через device.attributes у середовищі CEL.
  • Тип результату: expression має обчислюватися до скалярного значення (string, int, bool або семантичної версії) або, коли також увімкнено функціональну можливість DRAListTypeAttributes, до списку одного з цих скалярних типів.
  • Обмеження вартості: кожен вираз має максимальну довжину та обмеження на оцінену вартість обчислення CEL. Крім того, сукупна оцінена вартість усіх виразів derivedAttributes у ResourceClaim також обмежена, щоб обмежити загальні накладні витрати, додані до однієї спроби планування. ResourceClaim відхиляється, якщо будь-яке з цих обмежень перевищено.
  • Помилки виконання переривають планування: якщо обчислення виразу завершується помилкою для кандидата пристрою, наприклад, тому що він посилається на атрибут, якого цей пристрій не має, планувальник перериває виділення, і Pod не може бути запланований, замість того щоб мовчки пропустити цей пристрій. Пишіть вирази обережно, наприклад, перевіряючи, що атрибут існує, перед його читанням.

Похідні атрибути контролюються функціональною можливістю DRADerivedAttributes у kube-apiserver та kube-scheduler.

Список стандартних атрибутів пристроїв, які можуть публікувати драйвери DRA, див. у довіднику Стандартні атрибути пристроїв.

Розширене виділення ресурсів за допомогою DRA

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

Це стабільна функція в , яка загальнодоступна починаючи з версії 1.37. Вперше вона зʼявилась у випуску v1.34.

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

У наведеному нижче прикладі класу пристрою надано extendedResourceName example.com/gpu. Якщо Pod запитує розширений ресурс example.com/gpu: 2, його можна запланувати на вузол з двома або більше пристроями, які відповідають класу пристрою.

apiVersion: resource.k8s.io/v1
kind: DeviceClass
metadata:
  name: gpu.example.com
spec:
  selectors:
  - cel:
      expression: device.driver == 'gpu.example.com' && device.attributes['gpu.example.com'].type
        == 'gpu'
  extendedResourceName: example.com/gpu

На додачу, користувачі можуть використовувати спеціальний розширений ресурс для виділення пристроїв без необхідності явно створювати ResourceClaim. Використовуючи префікс імені розширеного ресурсу deviceclass.resource.kubernetes.io/ та імʼя DeviceClass. Це працює для будь-якого DeviceClass, навіть якщо він не вказує на імʼя розширеного ресурсу. Кінцевий ResourceClaim міститиме запит на ExactCount вказаної кількості пристроїв цього DeviceClass.

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

Для практичного ознайомлення із запитом розширених ресурсів див. Призначення розширених ресурсів контейнеру.

2.2 - Як працює 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.

2.3 - Спостережуваність динамічних ресурсів

Ця сторінка описує, як спостерігати за статусом і справністю ресурсів, які динамічно виділяються за допомогою DRA.

Спостережуваність динамічних ресурсів

Ви можете перевірити статус динамічно виділених ресурсів, використовуючи будь-який із наступних методів:

Метрики пристроїв kubelet

Служба gRPC PodResourcesLister kubelet дозволяє вам контролювати пристрої, що використовуються. Повідомлення DynamicResource надає інформацію, специфічну для динамічного виділення ресурсів, таку як назва пристрою та назва заявки. Детальніше див. Моніторинг ресурсів втулків пристроїв.

Статус пристрою ResourceClaim

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

Це стабільна функція в , яка загальнодоступна починаючи з версії 1.37. Вперше вона зʼявилась у випуску v1.32.

Драйвери DRA можуть повідомляти специфічні для драйвера дані статусу пристрою для кожного виділеного пристрою в полі status.devices заявки на ресурс. Наприклад, драйвер може перелічувати IP-адреси, призначені пристрою мережевого інтерфейсу. Оновлення цього поля вимагає спеціальних синтетичних дозволів RBAC, див. Посібник із зміцнення безпеки — динамічний розподіл ресурсів та Посилення безпеки динамічного розподілу ресурсів у вашому кластері.

Точність інформації, яку драйвер додає до поля status.devices заявки на ресурс, залежить від драйвера. Оцінюйте драйвери, щоб вирішити, чи можете ви покладатися на це поле як на єдине джерело інформації про пристрої.

Якщо ви вимкнете функціональну можливість DRAResourceClaimDeviceStatus, поле status.devices автоматично очищається під час зберігання заявки на ресурс. Статус пристрою заявки на ресурс підтримується, коли з боку драйвера DRA можливо оновити наявну заявку на ресурс, у якій встановлено поле status.devices.

У наведеному нижче прикладі поле status.devices заявки на ресурс було заповнено драйвером (resource-driver.example.com), відповідальним за керування виділеним пристроєм:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
metadata:
  name: macvlan-eth0
spec:
...
status:
  allocation:
    devices:
      results:
      - device: eth0
        driver: resource-driver.example.com
        pool: nic-worker-a
        request: macvlan-eth0
        shareID: 8e7acdf9-0290-4ecd-a801-a654b021d2b7
        consumedCapacity:
          resource-driver.example.com/bandwidth: 1G
  devices:
  - conditions:
    - lastTransitionTime: "2025-10-21T08:38:17Z"
      message: Device successfully allocated and assigned to the pod
      reason: NetworkReady
      status: "True"
      type: NetworkReady
    device: eth0
    driver: resource-driver.example.com
    networkData:
      hardwareAddress: 00:01:ec:84:fb:51
      interfaceName: net1
      ips:
      - 10.10.1.2/24
      - 2001:db8::1/64
    pool: nic-worker-a
    shareID: 8e7acdf9-0290-4ecd-a801-a654b021d2b7

Якщо пристрій не було виділено, запит драйвера на оновлення поля status.devices заявки на ресурс із цим пристроєм відхиляється. Коли пристрій вивільняється (видаляється з status.allocation.devices), відповідний запис у status.devices автоматично видаляється.

Детальніше про поле status.devices див. у довіднику API ResourceClaim.

Моніторинг справності пристроїв

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

Kubernetes надає механізм для моніторингу та звітування про справність динамічно виділених ресурсів інфраструктури. Для застосунків зі збереженям стану, що працюють на спеціалізованому обладнанні, критично важливо знати, коли пристрій вийшов з ладу або став несправним. Також корисно дізнаватися, чи відновлюється пристрій.

Щоб використовувати цю функціональність, функціональна можливість ResourceHealthStatus ResourceHealthStatus має бути увімкнена (бета та стандартно увімкнена з v1.36), а драйвер DRA має реалізовувати службу gRPC DRAResourceHealth.

Коли драйвер DRA виявляє, що виділений пристрій став несправним, він повідомляє цей статус назад до kubelet. Ця інформація про справність потім безпосередньо відображається в статусі Podʼа. kubelet заповнює поле allocatedResourcesStatus у статусі кожного контейнера, деталізуючи справність кожного пристрою, призначеного цьому контейнеру. Кожен запис про справність ресурсу може містити необовʼязкове поле message з додатковим контекстом, зрозумілим людині, про стан справності, наприклад, деталі помилки або причини збою.

Якщо kubelet не отримує оновлення про справність від драйвера DRA протягом періоду очікування, статус справності пристрою позначається як "Unknown". Драйвери DRA можуть налаштовувати цей період очікування для кожного пристрою окремо, встановлюючи поле health_check_timeout_seconds у повідомленні gRPC DeviceHealth. Якщо не вказано, kubelet використовує стандартний період очікування 30 секунд. Це дозволяє різним типам обладнання (наприклад, GPU, FPGA або пристроям зберігання) використовувати відповідні значення періоду очікування на основі їхніх характеристик звітування про справність.

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

Примітка:

Статус справності пристрою не оновлюється в статусі Podʼа після завершення роботи Podʼа (наприклад, у стані Failed).

Статус пулу ресурсів

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

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

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

Ви можете запитувати доступність пристроїв у пулах ресурсів за допомогою API ResourcePoolStatusRequest. Це забезпечує видимість того, скільки пристроїв доступно, виділено або недоступно в пулах ресурсів DRA вашого кластера.

Щоб перевірити статус пулу ресурсів:

  1. Створіть ResourcePoolStatusRequest, вказавши назву драйвера (обовʼязково) та, за бажанням, обмеження на кількість повернутих пулів. Ви також можете обмежити його одним пулом, вказавши назву пулу:

    apiVersion: resource.k8s.io/v1alpha3
    kind: ResourcePoolStatusRequest
    metadata:
      name: check-gpus
    spec:
      driver: example.com/gpu
      # Optional: filter to a specific pool
      # poolName: my-pool
      # Optional: limit number of pools returned (default: 100, max: 1000)
      # limit: 10
    
  2. Дочекайтеся, поки контролер обробить запит:

    kubectl wait --for=condition=Complete resourcepoolstatusrequest/check-gpus --timeout=30s
    
  3. Прочитайте статус, щоб побачити доступність пулу:

    kubectl get resourcepoolstatusrequest/check-gpus -o yaml
    

    Статус включає:

    • poolCount: загальна кількість пулів, що відповідають фільтру (може перевищувати кількість перелічених пулів, якщо результат обрізано обмеженням).
    • pools: список деталей пулів, кожен з яких містить:
      • driver та poolName: ідентифікують пул.
      • generation: останнє покоління пулу, яке спостерігалось в ResourceSlices.
      • resourceSliceCount: кількість ResourceSlices, що складають пул.
      • totalDevices: загальна кількість пристроїв у пулі.
      • allocatedDevices: пристрої, наразі виділені заявкам.
      • availableDevices: пристрої, доступні для виділення (totalDevices - allocatedDevices - unavailableDevices).
      • unavailableDevices: пристрої, недоступні через позначки taint або інші стани.
      • nodeName: вузол, повʼязаний із пулом, якщо такий є.
      • validationError: встановлюється, коли дані пулу не вдалося повністю перевірити (наприклад, під час розгортання покоління). Коли встановлено, поля кількості пристроїв можуть бути невстановленими.
      • partitionSummary: для пулів з пристроями, що розділяються на розділи, можливість виділення за типом розділу (див. Підсумок розділів).
      • shareableSummary: для пулів з пристроями, що можуть спільно використовуватися, сукупне використання ємності (див. Підсумок спільного використання).
    • conditions: включає типи умов Complete (успіх) або Failed (помилка).
  4. Видаліть запит, коли закінчите:

    kubectl delete resourcepoolstatusrequest/check-gpus
    

Обʼєкти ResourcePoolStatusRequest обробляються один раз контролером у kube-controller-manager. Специфікація є незмінною після створення, а весь обʼєкт стає незмінним після заповнення статусу. Щоб отримати оновлені дані про доступність, видаліть і перестворіть запит. Завершені запити автоматично очищаються через 1 годину.

Ця функція вимагає явних дозволів RBAC на ресурс ResourcePoolStatusRequest. Жодна стандартна ClusterRole не включає цей дозвіл.

Статус пулу ресурсів контролюється функціональною можливістю DRAResourcePoolStatus у kube-apiserver та kube-controller-manager.

Підсумок розділу

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

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

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

Один фізичний пристрій, такий як GPU, може бути опублікований як кілька типів розділів (наприклад, повний GPU проти половинного розділу MIG), які використовують ті самі спільні лічильники. Оскільки ці розділи конкурують за ту саму базову ємність, проста кількість пристроїв не показує, скільки пристроїв кожного типу ще можна виділити. Для пулів з пристроями, що розділяються на розділи представлення partitionSummary відповідає на це питання. Для кожного типу розділу воно повідомляє:

  • attribute: повне імʼя атрибута пристрою, значення якого групує цей запис. Це spec.partitionTypeAttribute обʼєкта ResourceSlice або spec.defaultPartitionTypeAttribute запиту, коли розділ не оголошує жодного.
  • type: значення цього атрибута на пристрої (наприклад, Full або Half).
  • total: кількість пристроїв цього типу розділу в пулі.
  • allocatable: скільки додаткових пристроїв цього типу розділу ще можна було б виділити з урахуванням поточного споживання спільних лічильників.

Названий атрибут має бути рядковим атрибутом. Якщо атрибут типу розділу пристрою, що розділяється на розділи, відсутній або не є рядком (наприклад, ціле число, булеве значення або версія), пул повідомляє про помилку перевірки замість підсумку розділів. Немає спеціальної обробки для атрибутів типу список; не-рядковий атрибут просто не є дійсним атрибутом типу розділу.

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

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
# ...
spec:
  # Кожен пристрій, що підтримує розділення на розділи, у цьому сегменті має цей атрибут; пристрої,
  # які мають однакове значення, несуть однакові витрати на спільний лічильник.
  partitionTypeAttribute: gpu.example.com/profile

Якщо драйвер ще не оновлено для оголошення partitionTypeAttribute, запит все одно може отримати підсумок розділів, вказавши резервний атрибут у своїй специфікації. Власний partitionTypeAttribute розділу завжди має перевагу; стандартне значення на рівні запиту застосовується лише до пристроїв, чий розділ не оголошує його:

apiVersion: resource.k8s.io/v1alpha3
kind: ResourcePoolStatusRequest
metadata:
  name: check-gpu-partitions
spec:
  driver: gpu.example.com
  # Запасний атрибут групування для фрагментів, у яких він не вказаний.
  defaultPartitionTypeAttribute: gpu.example.com/profile

Коли ні розділ, ні запит не вказують атрибут, пул з пристроями, що розділяються на розділи, не повідомляє partitionSummary.

Представлення partitionSummary контролюється функціональною можливістю DRAPartitionableDevicesType у kube-apiserver та kube-controller-manager, яка, своєю чергою, вимагає увімкнення функціональних можливостей DRAResourcePoolStatus та DRAPartitionableDevices.

Підсумок спільного використання

Для пулів, що містять пристрої, які можуть спільно використовуватися (пристрої, які встановлюють allowMultipleAllocations і можуть споживатися кількома заявками), shareableSummary повідомляє сукупне використання ємності в межах пулу:

  • fullyAvailableDevices: пристрої, що можуть спільно використовуватися, з неспожитою ємністю.
  • partiallyAvailableDevices: пристрої, що можуть спільно використовуватися, з частково спожитою ємністю.
  • capacity: для кожної назви ємності сукупні обсяги total, consumed та available (total мінус consumed, ніколи не відʼємне) у межах пулу.

shareableSummary заповнюється лише тоді, коли принаймні один пристрій у пулі може спільно використовуватися. Він є частиною функції статусу пулу ресурсів (функціональна можливість DRAResourcePoolStatus) і не вимагає DRAPartitionableDevicesType; пристрої, що можуть спільно використовуватися, які він підсумовує, походять із функції споживчої ємності.

Метадані пристроїв DRA в контейнерах

Стан функціоналу: Beta починаючи з Kubernetes v1.37

Драйвери DRA можуть надавати метадані пристроїв, такі як атрибути пристроїв (адреси шини PCI або UUID медійованих пристроїв) та мережеву конфігурацію, безпосередньо контейнерам у вигляді JSON-файлів. Це дозволяє застосункам дізнаватися інформацію про виділені пристрої без запитів до API Kubernetes або використання власних контролерів.

KEP-5304 визначає протокол метаданих пристроїв, якого драйвери мають дотримуватися, щоб застосунки бачили узгоджену структуру в різних драйверах і кластерах. Бібліотека втулка kubelet DRA реалізує цей протокол.

Метадані пристроїв підпорядковуються тим самим правилам, що й доступ до пристроїв: вони доступні всередині контейнера лише тоді, коли цей контейнер запитує пристрій. Детальніше див. Запит пристроїв у робочих навантаженнях за допомогою DRA.

Протокол метаданих пристроїв

Протокол складається з чотирьох правил:

  1. Шляхи до файлів. Файли метаданих розташовані всередині контейнерів у /var/run/kubernetes.io/dra-device-attributes. Для безпосередньо згаданої заявки на ресурс шлях має вигляд resourceclaims/<claimName>/<requestName>/<driverName>-metadata.json. Для заявки, створеної з шаблону заявки на ресурс, шлях має вигляд resourceclaimtemplates/<podClaimName>/<requestName>/<driverName>-metadata.json, де podClaimName — це pod.spec.resourceClaims[].name.

    Коли запит використовує список пріоритетів, для сегмента шляху <requestName> використовується лише назва запиту верхнього рівня. Поле requests[].name у файлі містить повне посилання <request>/<subrequest>, наприклад gpu/high-memory.

    Константи шляхів визначені в k8s.io/dynamic-resource-allocation/api/metadata.

  2. JSON API. Кожен файл є потоком одного або кількох обʼєктів DeviceMetadata. Кожен обʼєкт має apiVersion та kind, відповідно до домовленостей API Kubernetes. Ті самі метадані кодуються один раз для кожної налаштованої версії API в порядку, вибраному драйвером. Споживачі використовують першу версію, яку вони можуть декодувати, і пропускають невідомі версії. Пошкоджений обʼєкт у відомій версії є помилкою.

  3. Покоління. Початковий файл має metadata.generation, встановлене на 1. Кожне оновлення збільшує покоління, щоб споживачі могли виявляти зміни.

  4. Надання контейнеру. Бібліотека втулка kubelet DRA використовує CDI для bind-mount кожного файлу лише для читання. Інші реалізації можуть використовувати інший механізм, якщо файл зʼявляється за необхідним шляхом і є доступним лише для читання.

Увімкнення метаданих пристроїв у драйвері

Метадані пристроїв — це функція на стороні драйвера. Вона не має функціональної можливості Kubernetes і стандартно вимкнена у бібліотеці втулка kubelet DRA. Драйвер має увімкнути функцію та явно вибрати версії, які він записує:

kubeletplugin.EnableDeviceMetadata(true, []schema.GroupVersion{
	metadatav1beta1.SchemeGroupVersion,
	metadatav1alpha1.SchemeGroupVersion,
})

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

Для кожного підготовленого пристрою драйвер може заповнити Device.Metadata за допомогою kubeletplugin.DeviceMetadata. Драйвери мають включати атрибути, які вони публікують для цього пристрою в його ResourceSlice, щоб робочі навантаження бачили ту саму інформацію під час виконання. Драйвери можуть також включати атрибути, які мають значення лише під час виконання. Для мережевих пристроїв, драйвери можуть додавати назви інтерфейсів, IP-адреси та апаратні адреси після конфігурації CNI, викликаючи UpdateRequestMetadata.

Посилання на API втулка kubelet вище описують інтеграцію для авторів драйверів. Фреймворк DRA не визначає універсального прапора командного рядка, тому оператори кластерів вмикають функцію через конфігурацію розгортання, надану їхнім драйвером.

Коли увімкнено, бібліотека втулка kubelet DRA записує файли метаданих під час підготовки виділених пристроїв. Вона також записує специфікації CDI до /var/run/cdi за замовчуванням. Середовище виконання контейнерів має бути налаштоване на виявлення специфікацій CDI з цього каталогу. Бібліотека визначає мінімальну версію специфікації CDI, необхідну для кожної згенерованої специфікації.

Коли один запит виділяє пристрої від кількох драйверів DRA, кожен драйвер записує власний файл метаданих. Споживачі, які знають назву драйвера, мають побудувати точний шлях із назв заявки, запиту та драйвера. Споживачі Go можуть використовувати ReadResourceClaimMetadata або ReadResourceClaimTemplateMetadata, щоб прочитати та обʼєднати всі файли кожного драйвера для запиту.

Схема метаданих

Кожен обʼєкт у файлі метаданих відповідає API DeviceMetadata (metadata.resource.k8s.io/v1beta1).

Схема містить:

  • Стандартні метадані обʼєкта для заявки на ресурс, включаючи її назву, простір імен, UID та покоління метаданих.
  • Необовʼязкове podClaimName для заявки, згенерованої з шаблону заявки на ресурс.
  • Список запитів. Кожен запит має обовʼязкову назву та список виділених пристроїв.
  • Драйвер, пул та назву для кожного пристрою.
  • Необовʼязкові атрибути пристроїв та мережеві дані.

Значення атрибутів використовують те саме представлення, що й атрибути пристроїв ResourceSlice. Кожен атрибут має рівно одне скалярне значення (int, bool, string або version) або значення списку (ints, bools, strings або versions). Значення ємності пристроїв не включаються в метадані пристроїв.

Мережеві дані можуть містити interfaceName, ips та hardwareAddress. Про обмеження полів див. документацію API DeviceMetadata.

Наведений нижче приклад показує один обʼєкт у потоці метаданих для пристрою GPU, виділеного через шаблон заявки на ресурс:

{
  "kind": "DeviceMetadata",
  "apiVersion": "metadata.resource.k8s.io/v1beta1",
  "metadata": {
    "name": "pod0-gpu-2kqrd",
    "namespace": "gpu-test1",
    "uid": "c7e7b22e-239b-4498-b27c-7f1344481e14",
    "generation": 1
  },
  "podClaimName": "gpu",
  "requests": [
    {
      "name": "gpu",
      "devices": [
        {
          "driver": "gpu.example.com",
          "pool": "worker-0",
          "name": "gpu-0",
          "attributes": {
            "driverVersion": {
              "version": "1.0.0"
            },
            "index": {
              "int": 0
            },
            "model": {
              "string": "LATEST-GPU-MODEL"
            },
            "uuid": {
              "string": "gpu-18db0e85-99e9-c746-8531-ffeb86328b39"
            }
          }
        }
      ]
    }
  ]
}

Втулок kubelet DRA не перевіряє метадані перед їх записом. Споживачі Go можуть увімкнути згенеровану перевірку під час декодування потоку. Декодування та перевірка мають окремі результати: помилка перевірки не перешкоджає поверненню успішно декодованого обʼєкта. Про використання див. Доступ до метаданих пристроїв DRA.

Негайні та відкладені метадані

Для негайних метаданих драйвер надає атрибути або мережеві дані під час підготовки заявки. Втулок kubelet DRA записує файл із поколінням 1 до запуску контейнера, що споживає.

Для відкладених метаданих драйвер може підготувати пристрій без атрибутів або мережевих даних. Початковий файл із поколінням 1 містить ідентичність пристрою. Пізніше драйвер викликає UpdateRequestMetadata, щоб атомарно замінити повний потік і збільшити покоління. Оновлення вимагає існування початкового файлу. Якщо підготовка пристрою не повертає жодних пристроїв для запиту, фреймворк не створює ні файлу метаданих, ні пристрою CDI метаданих для цього запиту.

Метадані залишаються доступними для кожного контейнера, що їх споживає, протягом усього життєвого циклу цього контейнера. Фреймворк видаляє файли метаданих та специфікації CDI після скасування підготовки заявки.

Щоб дізнатися, як використовувати метадані пристроїв у ваших робочих навантаженнях, див. Доступ до метаданих пристроїв DRA.

Власні драйвери

Власні драйвери, які не використовують бібліотеку втулка kubelet DRA, мають самостійно реалізувати протокол метаданих пристроїв. Це включає запис версіонованого потоку DeviceMetadata за правильними шляхами, збільшення metadata.generation при кожному оновленні та надання файлів лише для читання через CDI або еквівалентний механізм.

2.4 - Функції DRA

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

Пристрої, що розділяються на розділи

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

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

В API ResourceSlice це представлено як список іменованих CounterSets, кожен з яких містить набір іменованих лічильників. Лічильники представляють ресурси, доступні на фізичному пристрої, які використовуються логічними пристроями, опублікованими через DRA.

Логічні пристрої можуть вказувати список ConsumesCounters. Кожен запис містить посилання на CounterSet та набір іменованих лічильників із кількостями, які вони споживатимуть. Отже, щоб пристрій можна було виділити, згадані набори лічильників повинні мати достатню кількість для лічильників, на які посилається пристрій.

CounterSets мають бути вказані в окремих ResourceSlices від пристроїв. Пристрої можуть споживати лічильники з будь-якого CounterSet, визначеного в тому самому пулі ресурсів, що й пристрій.

Ось приклад двох пристроїв, кожен з яких споживає 6Gi памʼяті зі спільного лічильника з 8Gi памʼяті. Таким чином, лише один із пристроїв може бути виділений у будь-який момент часу. Планувальник обробляє це, і це прозоро для споживача, оскільки API ResourceClaim не змінюється.

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: resourceslice-with-countersets
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 2
  driver: dra.example.com
  sharedCounters:
  - name: gpu-1-counters
    counters:
      memory:
        value: 8Gi
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: resourceslice-with-devices
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 2
  driver: dra.example.com
  devices:
  - name: device-1
    consumesCounters:
    - counterSet: gpu-1-counters
      counters:
        memory:
          value: 6Gi
  - name: device-2
    consumesCounters:
    - counterSet: gpu-1-counters
      counters:
        memory:
          value: 6Gi

Пристрої, що розділяються на розділи, контролюються функціональною можливістю DRAPartitionableDevices у kube-apiserver та kube-scheduler.

Групи сумісності пристроїв

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

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

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

Групи сумісності пристроїв дозволяють драйверу DRA оголошувати, які розділені пристрої можуть бути спільно виділені на тому самому фізичному обладнанні. Без цієї функції несумісні комбінації пристроїв виявляються лише тоді, коли kubelet готує Pod на вузлі — що призводить до невдалої підготовки. З групами сумісності планувальник відхиляє несумісні комбінації на етапі планування, до початку будь-якої роботи на стороні вузла.

Це найбільш корисно для обладнання, яке підтримує взаємовиключні режими роботи. Наприклад, GPU, який може працювати в режимі MIG або в режимі vGPU: пристрій у режимі MIG та пристрій у режимі vGPU не можуть бути спільно виділені, оскільки вони споживають ті самі фізичні ресурси несумісним чином. Оголошуючи compatibilityGroups, драйвер робить це обмеження видимим для планувальника.

Ця функція ґрунтується на пристроях, що розділяються на розділи: поле compatibilityGroups знаходиться в записах device.consumesCounters[], які існують лише для пристроїв, що розділяються на розділи. Обидві функціональні можливості DRADeviceCompatibilityGroups та DRAPartitionableDevices мають бути увімкнені в kube-apiserver та kube-scheduler.

Як це працює

Драйвер визначає список compatibilityGroups для кожного запису device.consumesCounters[] у ResourceSlice. Список містить щонайбільше 2 непрозорі рядкові назви, які представляють режим роботи або тип розділу цього пристрою на цьому конкретному наборі лічильників.

Коли планувальник виділяє кілька пристроїв, які використовують той самий набір лічильників, він обчислює перетин їхніх compatibilityGroups. Виділення успішне лише тоді, коли цей перетин не порожній — тобто кожен спільно виділений пристрій має принаймні одну спільну назву групи. Пристрої, які використовують різні набори лічильників, ніколи не порівнюються між собою.

Пристрій, який не оголошує жодних груп (невстановлений, nil або порожній список), розглядається як особливий випадок: він може бути спільно виділений лише з іншими пристроями без груп на тому самому наборі лічильників. Він ніколи не може бути спільно виділений з пристроєм, який оголошує одну або більше груп.

Обмеження застосовується до всіх заявок, що виділяються в одному циклі планування: якщо дві заявки кожна виділяє пристрій з того самого набору лічильників, перетин груп між заявками також забезпечується.

Приклад

Розглянемо GPU, який може працювати в режимі MIG або в режимі vGPU. Драйвер публікує два пристрої, кожен з яких споживає 4 GiB з того самого спільного лічильника памʼяті обсягом 8 GiB. Лише на основі ємності лічильника обидва пристрої могли б бути виділені разом. Кожен пристрій оголошує свій режим роботи як групу сумісності, роблячи два режими взаємовиключними:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: gpu-counters
spec:
  nodeName: worker-1
  pool:
    name: gpu-pool
    generation: 1
    resourceSliceCount: 2
  driver: gpu.example.com
  sharedCounters:
  - name: gpu-0-memory
    counters:
      memory:
        value: 8Gi
---
apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: gpu-devices
spec:
  nodeName: worker-1
  pool:
    name: gpu-pool
    generation: 1
    resourceSliceCount: 2
  driver: gpu.example.com
  devices:
  - name: gpu-0-mig
    consumesCounters:
    - counterSet: gpu-0-memory
      counters:
        memory:
          value: 4Gi
      compatibilityGroups:
      - mig
  - name: gpu-0-vgpu
    consumesCounters:
    - counterSet: gpu-0-memory
      counters:
        memory:
          value: 4Gi
      compatibilityGroups:
      - vgpu

У цьому прикладі:

  • gpu-0-mig належить до групи mig.
  • gpu-0-vgpu належить до групи vgpu.

Якщо Pod або PodGroup запитує два пристрої з цього пулу, планувальник перевіряє, чи мають два вибрані пристрої спільну групу сумісності на наборі лічильників gpu-0-memory. Оскільки {"mig"} ∩ {"vgpu"} = ∅, пара відхиляється — навіть якщо набір лічильників має достатньо памʼяті для обох. Обидва запити можуть бути задоволені лише двома пристроями MIG (або двома пристроями vGPU) з пулу, де такі пари існують.

Обмеження

  • Кожен запис consumesCounters[] може оголошувати щонайбільше 2 назви груп.
  • Назви груп мають бути унікальними в межах одного запису.
  • Назви груп є непрозорими для Kubernetes; вони мають значення лише в межах пулу драйвера, що їх публікує.
  • Групи порівнюються для кожного набору лічильників окремо: групи на одному наборі лічильників не впливають на рішення про спільне виділення для іншого набору лічильників.

Безпека при різниці версій

Коли функціональну можливість DRADeviceCompatibilityGroups вимкнено (стандартно для альфа), kube-apiserver видаляє поле compatibilityGroups з будь-якого нового або оновленого ResourceSlice — якщо старий обʼєкт уже не мав цього поля встановленим. Тоді планувальник розглядає пристрої в будь-якому пулі, який раніше мав згруповані пристрої, як такі, що належать до неповного пулу, і повністю пропускає їх.

Лише непорожній список вважається встановленим полем: compatibilityGroups: null та compatibilityGroups: [] обробляються так само, як і пропуск поля. Пристрої з ними поводяться точно так само, як пристрої без груп — вони не змушують планувальник вважати пул неповним.

Групи сумісності пристроїв контролюються функціональною можливістю DRADeviceCompatibilityGroups у kube-apiserver та kube-scheduler. Функціональна можливість DRAPartitionableDevices також має бути увімкнена.

Споживча ємність

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

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

Драйвер пристрою може встановити поле allowMultipleAllocations, додане в .spec.devices обʼєкта ResourceSlice, щоб дозволити виділення цього пристрою кільком незалежним заявкам на ресурси або кільком запитам у межах однієї заявки на ресурс.

Користувачі можуть встановити поле capacity, додане в spec.devices.requests обʼєкта ResourceClaim, щоб вказати вимоги до ресурсів пристрою для кожного виділення.

Для пристрою, який дозволяє кілька виділень, запитана ємність береться з, або споживається з, його загальної ємності, концепція, відома як споживча ємність. Тоді планувальник гарантує, що сукупна спожита ємність у всіх заявках не перевищує загальну ємність пристрою. Крім того, автори драйверів можуть використовувати обмеження requestPolicy для окремих ємностей пристроїв, щоб контролювати, як ці ємності споживаються. Наприклад, автор драйвера може вказати, що певна ємність споживається лише приростами по 1Gi.

Ось приклад мережевого пристрою, який дозволяє кілька виділень і містить споживчу ємність пропускної здатності.

kind: ResourceSlice
apiVersion: resource.k8s.io/v1
metadata:
  name: resourceslice
spec:
  nodeName: worker-1
  pool:
    name: pool
    generation: 1
    resourceSliceCount: 1
  driver: dra.example.com
  devices:
  - name: eth1
    allowMultipleAllocations: true
    attributes:
      name:
        string: "eth1"
    capacity:
      bandwidth:
        requestPolicy:
          default: "1M"
          validRange:
            min: "1M"
            step: "8"
        value: "10G"

Споживчу ємність можна запитати, як показано в прикладі нижче.

apiVersion: resource.k8s.io/v1
kind: ResourceClaimTemplate
metadata:
  name: bandwidth-claim-template
spec:
  spec:
    devices:
      requests:
      - name: req-0
        exactly:
          deviceClassName: resource.example.com
          capacity:
            requests:
              bandwidth: 1G

Результат виділення міститиме спожиту ємність та ідентифікатор частки.

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
...
status:
  allocation:
    devices:
      results:
      - consumedCapacity:
          bandwidth: 1G
        device: eth1
        shareID: "a671734a-e8e5-11e4-8fde-42010af09327"

У цьому прикладі було вибрано пристрій, який допускає кілька виділень. Однак будь-який пристрій resource.example.com із принаймні запитаною пропускною здатністю 1G міг би задовольнити вимогу. Якби було вибрано пристрій, який не допускає кілька виділень, виділення призвело б до використання всього пристрою. Щоб примусово використовувати лише пристрої, які допускають кілька виділень, ви можете використати критерій CEL device.allowMultipleAllocations == true.

Обмеження DistinctAttribute

Коли ви запитуєте кілька пристроїв у заявці на ресурс, ви можете використати обмеження DistinctAttribute, щоб гарантувати, що кожен виділений пристрій має різне значення для вказаного атрибута. Це обмеження було введено разом із функцією споживчої ємності.

Обмеження DistinctAttribute особливо корисне під час роботи з пристроями, які допускають кілька виділень. Воно запобігає виділенню одного й того самого пристрою кілька разів у межах однієї заявки на ресурс, навіть якщо цей пристрій дозволяє кілька виділень.

Окрім запобігання дублюванню виділень, це обмеження допомагає оптимізувати продуктивність, гарантуючи розподіл пристроїв на основі їхніх атрибутів. Наприклад, ви можете використати його для розподілу пристроїв між різними NUMA-вузлами, щоб оптимізувати пропускну здатність памʼяті та зменшити конкуренцію.

Авторизація на основі детального статусу

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

Починаючи з Kubernetes v1.36, DRA застосовує детальні перевірки авторизації для оновлень статусу ResourceClaim, використовуючи синтетичні субресурси та дієслова, що враховують вузли.

Інструкції з посилення безпеки, включаючи приклади RBAC для планувальника та драйверів DRA, див. у Посібнику із зміцнення безпеки — динамічний розподіл ресурсів.

Покрокову процедуру для адміністратора кластера див. у Посиленні безпеки динамічного розподілу ресурсів у вашому кластері.

Необовʼязкові операції з вузлами

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

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

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

У динамічному виділенні ресурсів (DRA) kubelet координується з локальним для вузла драйвером через gRPC, щоб підготувати виділені пристрої перед запуском контейнера (NodePrepareResources) та скасувати їх підготовку після завершення роботи Podʼа (NodeUnprepareResources). Хоча така схема є критичною для локального для вузла обладнання, такого як GPU або FPGA, деякі ресурси керуються повністю в панелі управління і не потребують жодної локальної настройки на вузлі.

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

Конфігурація драйвера

Автори драйверів можуть вказати поле skipNodeOperations у .spec.skipNodeOperations обʼєкта ResourceSlice. Це поле є списком унікальних рядків, які вказують локальні для вузла операції, що мають бути пропущені для всіх пристроїв у цьому розділі.

Допустимі значення:

  • "NodePrepareResources": пропускає виклики gRPC NodePrepareResources. Це значення не можна вказати, якщо "NodeUnprepareResources" також не вказано (або не вказано "*"). Це обмеження запобігає застряганню Podʼів у стані Terminating, якщо локальний для вузла втулок відсутній, оскільки втулок не перевіряється під час запуску Podʼа, коли підготовку пропущено.
  • "NodeUnprepareResources": пропускає виклики gRPC NodeUnprepareResources.
  • "*": пропускає всі локальні для вузла операції з ресурсами.

Ось приклад ResourceSlice для ресурсу панелі управління, який пропускає всі локальні для вузла операції:

apiVersion: resource.k8s.io/v1
kind: ResourceSlice
metadata:
  name: control-plane-resources
spec:
  nodeName: worker-1
  pool:
    name: central-pool
    generation: 1
    resourceSliceCount: 1
  driver: control-plane.example.com
  skipNodeOperations:
  - "*"
  devices:
  - name: virtual-device-1

Результат виділення та виконання

Коли планувальник Kubernetes виділяє пристрій заявці на ресурс, він копіює список skipNodeOperations з ResourceSlice у результат виділення:

apiVersion: resource.k8s.io/v1
kind: ResourceClaim
...
status:
  allocation:
    devices:
      results:
      - device: virtual-device-1
        driver: control-plane.example.com
        pool: central-pool
        skipNodeOperations:
        - "*"

Коли Pod працює на вузлі, kubelet читає результати виділення. Якщо всі виділені пристрої для певного драйвера в межах заявки на ресурс пропускають конкретну операцію, kubelet повністю оминає виклик цього хука gRPC для цього драйвера.

Експлуатаційні міркування

Оновлення драйвера на місці

Оскільки налаштування skipNodeOperations копіюється з ResourceSlice у заявку на ресурс під час виділення, запущені Podʼи та активні виділення зберігають те налаштування, яке діяло на момент їх планування.

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

Інтеграція з оголошеними функціями вузла

Щоб запобігти плануванню Podʼів на вузлах, де kubelet не підтримує пропуск операцій DRA (що призвело б до збою kubelet в очікуванні відсутнього втулка вузла), ця функція інтегрується з Оголошеними функціями вузла. Коли Pod використовує заявку на ресурс із налаштованим skipNodeOperations, планувальник Kubernetes перевіряє, що цільовий вузол оголошує підтримку функції DRAOptionalNodeOperations у своєму .status.declaredFeatures, перш ніж планувати Pod.

Необовʼязкові операції з вузлами контролюються функціональною можливістю DRAOptionalNodeOperations у kube-apiserver, kube-scheduler та kubelet.

Метадані пристроїв DRA в контейнерах

Стан функціоналу: Alpha починаючи з Kubernetes v1.36

Драйвери DRA можуть надавати метадані пристроїв, такі як атрибути пристроїв (адреси шини PCI або mdevUUID для пристроїв з опосередкованим керуванням) або мережеву конфігурацію, безпосередньо контейнерам у вигляді JSON-файлів. Це дозволяє застосункам усередині контейнера дізнаватися інформацію про виділені пристрої без запитів до API Kubernetes або створення власних контролерів.

KEP-5304 визначає протокол метаданих пристроїв, якого драйвери мають дотримуватися, щоб застосунки всередині контейнера бачили узгоджену структуру в різних драйверах і кластерах. Бібліотека втулка kubelet DRA реалізує цей протокол за вас; решта цього розділу описує, як ним користуватися.

Метадані пристроїв підпорядковуються тим самим правилам, що й доступ до пристроїв: вони доступні всередині контейнера лише тоді, коли цей контейнер запитує пристрій у своїй специфікації контейнера, і не інакше. Інструкції щодо запиту пристроїв DRA в Podʼах і контейнерах див. у Запиті пристроїв у робочих навантаженнях за допомогою DRA.

Протокол метаданих пристроїв

Протокол складається з чотирьох правил:

  1. Шляхи до файлів. Файли метаданих розташовані всередині контейнерів у /var/run/kubernetes.io/dra-device-attributes. Для безпосередньо згаданої заявки на ресурс шлях має вигляд resourceclaims/<claimName>/<requestName>/<driverName>-metadata.json; для заявки, створеної з шаблону заявки на ресурс, шлях має вигляд resourceclaimtemplates/<podClaimName>/<requestName>/<driverName>-metadata.json (де podClaimName — це pod.spec.resourceClaims[].name).

    У випадках, коли запит заявки на ресурс використовує функцію списку пріоритетів, для сегмента <requestName> у шляху до файлу використовується лише назва запиту верхнього рівня (тобто частина /<subrequest> відкидається). Усередині JSON-файлу поле requests[].name містить повне посилання <request>/<subrequest> (наприклад, gpu/high-memory), щоб споживачі могли визначити, яку альтернативу було виділено.

    Константи шляхів визначені в k8s.io/dynamic-resource-allocation/api/metadata.

  2. JSON API. Кожен файл є потоком одного або кількох обʼєктів DeviceMetadata, серіалізованих як версіонований JSON з apiVersion та kind, відповідно до конвенцій API Kubernetes. Ті самі метадані кодуються один раз для кожної підтримуваної версії API (спочатку найновіша). Усі обʼєкти в потоці семантично еквівалентні; споживачі мають використовувати перший обʼєкт, який вони можуть декодувати.

  3. Покоління. Коли драйвер оновлює файл метаданих, вбудоване поле metadata.generation має збільшуватися, щоб споживачі могли виявляти зміни.

  4. Надання контейнеру. Файли зазвичай надаються через CDI bind-mount, але інші механізми дозволені, якщо файл зʼявляється за правильним шляхом і є доступним лише для читання всередині контейнера.

Як працюють метадані пристроїв

Метадані пристроїв — це функція на стороні драйвера, яка не потребує жодних змін API Kubernetes або функціональних можливостей. Використання бібліотеки втулка kubelet DRA є поширеним способом реалізації драйвера, але драйвери можуть бути створені й іншими способами. Драйвери, які використовують втулок kubelet, вмикають цю функцію, передаючи опції EnableDeviceMetadata та MetadataVersions під час запуску втулка. MetadataVersions визначає, які версії API серіалізуються у файл метаданих, і має бути явно встановлена драйвером. Перегляньте документацію вашого драйвера DRA, щоб дізнатися, чи підтримуються метадані пристроїв і як їх увімкнути.

Коли метадані пристроїв увімкнено, драйвер генерує файли метаданих та специфікації CDI bind-mount під час підготовки виділених пристроїв для podʼа, до запуску контейнерів, що їх споживають. Метадані зʼявляються всередині контейнерів за добре відомими шляхами, як визначено вище.

Коли один запит виділяє пристрої від кількох драйверів DRA, кожен драйвер записує власний файл метаданих. Контейнери перелічують файли *-metadata.json у теці запиту, щоб виявити всі пристрої.

Пакунок Go k8s.io/dynamic-resource-allocation/devicemetadata надає утиліти для читання та декодування цих файлів метаданих застосунками всередині контейнера.

Схема метаданих

Кожен файл метаданих відповідає API DeviceMetadata (metadata.resource.k8s.io/v1alpha1). Наведений нижче приклад показує файл метаданих для пристрою GPU, виділеного через шаблон заявки на ресурс:

{
  "kind": "DeviceMetadata",
  "apiVersion": "metadata.resource.k8s.io/v1alpha1",
  "metadata": {
    "name": "pod0-gpu-2kqrd",
    "namespace": "gpu-test1",
    "uid": "c7e7b22e-239b-4498-b27c-7f1344481e14",
    "generation": 1
  },
  "podClaimName": "gpu",
  "requests": [
    {
      "name": "gpu",
      "devices": [
        {
          "driver": "gpu.example.com",
          "pool": "worker-0",
          "name": "gpu-0",
          "attributes": {
            "driverVersion": {
              "version": "1.0.0"
            },
            "index": {
              "int": 0
            },
            "model": {
              "string": "LATEST-GPU-MODEL"
            },
            "uuid": {
              "string": "gpu-18db0e85-99e9-c746-8531-ffeb86328b39"
            }
          }
        }
      ]
    }
  ]
}

Негайні та відкладені метадані

Драйвери надають метадані одним із двох способів:

Негайні
Драйвер заповнює метадані під час підготовки заявки на вузлі та записує файл метаданих до запуску контейнера. Це типово для драйверів GPU, де інформація про пристрій відома на момент підготовки.
Відкладені
У деяких випадках, наприклад для мережевого драйвера, інформація про пристрій недоступна під час виділення пристрою, але стає доступною після створення пісочниці podʼа. У таких випадках драйвер створює CDI-монтування з порожнім файлом метаданих і записує фактичні метадані пізніше через хук NRI, який виконується перед запуском контейнера. Це гарантує, що застосунки ніколи не побачать відсутній або частково записаний файл. Кожне оновлення має збільшувати metadata.generation, щоб споживачі могли виявляти зміни. API MetadataUpdater у бібліотеці втулка kubelet DRA автоматично обробляє облік поколінь для авторів драйверів.

В обох випадках метадані залишаються доступними для кожного контейнера, що їх споживає, протягом усього життєвого циклу цього контейнера. Файли метаданих видаляються після завершення роботи всіх контейнерів у Podʼі.

Щоб дізнатися, як використовувати метадані пристроїв у ваших робочих навантаженнях, див. Доступ до метаданих пристроїв DRA.

Власні драйвери

Власні, створені вручну драйвери, які не використовують бібліотеку втулка kubelet DRA, мають самостійно реалізувати протокол метаданих пристроїв. Це означає запис JSON DeviceMetadata за правильними шляхами до файлів, збільшення metadata.generation при кожному оновленні та надання файлів лише для читання всередині контейнера через CDI або еквівалентний механізм.

2.5 - Позначки Taint та Toleration пристроїв

Ця сторінка описує позначки taint та toleration пристроїв в DRA, які дозволяють драйверам та адміністраторам не допускати Podʼи до певних пристроїв або виселяти Podʼи, які вже їх використовують.

Позначки taint та toleration пристроїв

Стан функціоналу: Stable починаючи з Kubernetes v1.37
Докладніше про цей функціонал

Це стабільна функція в Kubernetes, яка загальнодоступна починаючи з версії v1.37. Вперше вона зʼявилась у випуску v1.33. Ви більше не можете вимкнути або відмовитися від цієї функції чи поведінки (це заблоковано); якщо ви явно встановите значення для повʼязаної функціональної можливості DRADeviceTaints, Kubernetes проігнорує це, але не повідомить про помилку.

Позначки taint пристроїв схожі на позначки taint вузлів: taint має рядковий ключ, рядкове значення та ефект. Ефект застосовується до заявки на ресурс, яка використовує позначений пристрій, і до всіх Podʼів, які посилаються на цю заявку на ресурс. Ефект "NoSchedule" запобігає плануванню цих Podʼів. Позначені пристрої ігноруються під час спроби виділити заявку на ресурс, оскільки їх використання перешкоджало б плануванню Podʼів.

Ефект "NoExecute" передбачає "NoSchedule" і, крім того, спричиняє виселення всіх Podʼів, які вже були заплановані. Це виселення реалізовано в контролері виселення за позначками taint пристроїв у kube-controller-manager шляхом видалення відповідних Podʼів.

Ефект "None" ігнорується планувальником і контролером виселення. Драйвери DRA можуть використовувати його для передачі виняткових ситуацій адміністраторам або іншим контролерам, наприклад, погіршення справності пристрою. Адміністратори також можуть використовувати його для пробних запусків виселення подів у DeviceTaintRules (детальніше про це нижче).

Заявки на ресурси можуть толерувати позначки taint. Якщо taint толерується, його ефект не застосовується. Порожня толерантність відповідає всім позначкам taint. Толерантність може бути обмежена певними ефектами та/або відповідати певним парам ключ/значення. Толерантність може перевіряти, що певний ключ існує, незалежно від того, яке значення він має, або вона може перевіряти конкретні значення ключа. Детальніше про це зіставлення див. у концепціях taint вузлів.

Виселення може бути відкладене шляхом толерування taint протягом певного періоду часу. Ця затримка починається в момент, коли taint додається до пристрою, що фіксується в полі taint.

Позначки taint застосовуються, як описано вище, також до заявок на ресурси, які виділяють "всі" пристрої на вузлі. Усі пристрої мають бути непозначеними, або всі їхні позначки taint мають толеруватися. Виділення пристрою з адміністративним доступом (описано вище) також не є винятком. Адміністратор, який використовує цей режим, має явно толерувати всі позначки taint, щоб отримати доступ до позначених пристроїв.

Ви можете додавати позначки taint до пристроїв наступними способами, використовуючи вид API DeviceTaintRule.

Позначки taint, встановлені драйвером

Драйвер DRA може додавати позначки taint до інформації про пристрій, яку він публікує в ResourceSlices. Зверніться до документації драйвера DRA, щоб дізнатися, чи використовує драйвер позначки taint і які їхні ключі та значення.

Позначки taint, встановлені адміністратором

Стан функціоналу: Stable починаючи з Kubernetes v1.37
Докладніше про цей функціонал

Це стабільна функція в Kubernetes, яка загальнодоступна починаючи з версії v1.37. Вперше вона зʼявилась у випуску v1.35. Ви більше не можете вимкнути або відмовитися від цієї функції чи поведінки (це заблоковано); якщо ви явно встановите значення для повʼязаної функціональної можливості DRADeviceTaintRules, Kubernetes проігнорує це, але не повідомить про помилку.

Адміністратор або компонент панелі управління може позначити пристрої без необхідності вказувати драйверу DRA включати позначки taint у свою інформацію про пристрої в ResourceSlices. Вони роблять це, створюючи DeviceTaintRules. Кожен DeviceTaintRule додає одну позначку taint пристроям, які відповідають селектору пристроїв. Без такого селектора жодні пристрої не позначаються. Це ускладнює випадкове виселення всіх подів, які використовують заявки на ресурси, якщо селектор випадково пропущено.

Пристрої можуть бути вибрані шляхом вказання назви DeviceClass, драйвера, пулу та/або пристрою. DeviceClass вибирає всі пристрої, які вибираються селекторами в цьому DeviceClass. Лише з назвою драйвера адміністратор може позначити всі пристрої, якими керує цей драйвер, наприклад, під час проведення певного технічного обслуговування цього драйвера в усьому кластері. Додавання назви пулу може обмежити taint одним вузлом, якщо драйвер керує локальними для вузла пристроями.

Нарешті, додавання назви пристрою може вибрати один конкретний пристрій. Назва пристрою та назва пулу також можуть використовуватися окремо, якщо бажано. Наприклад, драйверам для локальних для вузла пристроїв рекомендується використовувати назву вузла як назву свого пулу. Тоді позначення за допомогою цієї назви пулу автоматично позначає всі пристрої на вузлі.

Драйвери можуть використовувати стабільні назви, як-от "gpu-0", які приховують, який саме пристрій наразі призначено цій назві. Щоб підтримати позначення конкретного екземпляра обладнання, у DeviceTaintRule можна використовувати селектори CEL для зіставлення з унікальним ID-атрибутом, специфічним для постачальника, якщо драйвер підтримує його для свого обладнання.

Taint застосовується, доки існує DeviceTaintRule. Його можна змінювати та видаляти в будь-який час. Ось один приклад DeviceTaintRule для вигаданого драйвера DRA:

apiVersion: resource.k8s.io/v1
kind: DeviceTaintRule
metadata:
  name: example
spec:
  # Уся апаратна інсталяція для цього
  # конкретного драйвера не працює.
  # Припинити роботу всіх подів і не планувати запуск нових.
  deviceSelector:
    driver: dra.example.com
  taint:
    key: dra.example.com/unhealthy
    value: Broken
    effect: NoExecute

kube-apiserver автоматично відстежує, коли було створено цю позначку taint, встановлюючи поле timeAdded у spec. Період толерантності починається з цієї позначки часу. Під час оновлень, які змінюють ефект (див. імітований процес виселення нижче), kube-apiserver автоматично оновлює позначку часу. Користувачі можуть контролювати позначку часу явно, встановлюючи поле під час створення DeviceTaintRule та змінюючи його на інше значення під час оновлення.

Статус містить стан, доданий контролером виселення:

kubectl describe devicetaintrules
Name:         example
...
Spec:
  Device Selector:
    Driver:  dra.example.com
  Taint:
    Effect:      NoExecute
    Key:         dra.example.com/unhealthy
    Time Added:  2025-11-05T18:15:37Z
    Value:       Broken
Status:
  Conditions:
    Last Transition Time:  2025-11-05T18:15:37Z
    Message:               1 pod evicted since starting the controller.
    Observed Generation:   1
    Reason:                Completed
    Status:                False
    Type:                  EvictionInProgress
Events:                    <none>

Podʼи виселяються шляхом їх видалення. Зазвичай це відбувається дуже швидко, за винятком випадків, коли толерантність до taint відкладає це на певний період або коли є дуже багато подів, які потрібно виселити. Коли це займає більше часу, повідомлення надає інформацію про поточний статус:

2 pods need to be evicted in 2 different namespaces. 1 pod evicted since starting the controller.

Стан може використовуватися для перевірки того, чи виселення наразі активне:

kubectl wait --for=condition=EvictionInProgress=false DeviceTaintRule/example

Стережіться потенційної гонитви між планувальником і контролером, які спостерігають нову позначку taint у різний час, що може призвести до того, що поди все ще плануватимуться в момент, коли контролер вважає, що немає жодних, які потрібно виселити, і тому встановлює цей стан в False. На практиці ця гонитва стає дуже малоймовірною завдяки оновленню статусу лише після навмисної затримки в кілька секунд.

Для effect: None повідомлення надає інформацію про кількість відповідних пристроїв, скільки з них виділено та скільки podʼів було б виселено, якби ефект був NoExecute. Це можна використовувати для пробного запуску перед фактичним запуском виселення:

  • Створіть DeviceTaintRule з бажаними селекторами та effect: None.

  • Перегляньте повідомлення:

3 published devices selected. 1 allocated device selected.
1 pod would be evicted in 1 namespace if the effect was NoExecute.
This information will not be updated again. Recreate the DeviceTaintRule to trigger an update.

Опубліковані пристрої — це ті, що перелічені в ResourceSlices. Їх позначення запобігає виділенню для нових подів. Лише виділені пристрої спричиняють виселення подів, які їх використовують.

  • Відредагуйте DeviceTaintRule та змініть ефект на NoExecute.

3 - Керування ресурсами на рівні Podʼів

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

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

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

Підтримка ресурсів на рівні Podʼів для наявних менеджерів ресурсів (Topology, CPU та Memory) розширює їх для роботи зі специфікаціями ресурсів на рівні Podʼів. Коли цю функцію увімкнено (через функціональні можливості PodLevelResources та PodLevelResourceManagers), менеджери ресурсів можуть використовувати .spec.resources безпосередньо як основу для своїх рішень щодо виділення, еволюціонуючи від суто поконтейнерної моделі виділення до Pod-центричної. Ця схема розділення впроваджує більш гнучку та потужну модель керування ресурсами, особливо для чутливих до продуктивності робочих навантажень. Вона дозволяє визначати гібридні моделі виділення, у яких деякі контейнери в Podʼі отримують ексклюзивні, вирівняні за NUMA ресурси, тоді як інші спільно використовують решту ресурсів зі спільного пулу на рівні Podʼа.

Щоб попрактикуватися в налаштуванні менеджерів ресурсів kubelet з ресурсами на рівні Podʼів і на власні очі спостерігати за поведінкою виділення, ознайомтесь з навчальним посібником Використання ресурсів на рівні Podʼів з менеджерами ресурсів kubelet.

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

Менеджери ресурсів на рівні Podʼів використовують .spec.resources, щоб увімкнути гнучке розділення на основі налаштованої області дії менеджера топології:

  • Область дії pod: kubelet виділяє та вирівнює за NUMA єдину «бульбашку» Pod для всього Podʼа на основі .spec.resources. Контейнери, які запитують ексклюзивні виділення, виділяють собі окремі сегменти всередині цієї «бульбашки» Pod, тоді як усі інші контейнери спільно використовують решту ємності «бульбашки» у загальному пулі, ізольованому на рівні Pod.
  • Область дії container: вмикає гібридну модель виділення. kubelet дозволяє окремим контейнерам отримувати ексклюзивні, вирівняні за NUMA ресурси безпосередньо з пулу, доступного для виділення на вузлі, використовуючи стелю .spec.resources Podʼа для обмеження сукупного споживання — що дозволяє sidecars працювати в загальному спільному пулі вузла без необхідності, щоб кожен контейнер у Podʼі був Guaranteed.

Як стандартні init-контейнери, так і init-контейнери з можливістю перезапуску (sidecar) повністю підтримуються. Вони можуть отримувати ексклюзивні частки ресурсів або використовувати спільний пул Podʼа, а менеджери ресурсів на рівні Podʼів дотримуються їхніх правил життєвого циклу (наприклад, повторно використовувані ресурси для стандартних init-контейнерів проти постійних резервувань для сайдкарів).

Глосарій

Специфікація ресурсів на рівні Podʼа
Бюджет ресурсів, визначений на рівні Podʼа в .spec.resources, який визначає сукупні запити та ліміти для всього Podʼа.
Контейнер Guaranteed
Контейнер, який визначає запити ресурсів, рівні його лімітам, як для CPU (ексклюзивне виділення CPU вимагає додатного цілого значення), так і для памʼяті. Відповідно до наявної поведінки kubelet, це робить контейнер придатним для ексклюзивного виділення ресурсів менеджерами ресурсів.
Ексклюзивна частка
Виділена частина ресурсів (наприклад, конкретні CPU або сторінки памʼяті), призначена виключно одному контейнеру, що забезпечує ізоляцію від інших контейнерів.
Спільний пул Podʼа
Підмножина виділених ресурсів Podʼа, яка залишається після резервування всіх ексклюзивних часток. Ці ресурси спільно використовуються всіма контейнерами в Podʼі, які не отримують ексклюзивного виділення. Хоча контейнери в цьому пулі спільно використовують ресурси один з одним, вони суворо ізольовані від ексклюзивних часток і загального спільного пулу вузла.

Як працюють менеджери ресурсів на рівні Podʼів

Менеджери ресурсів CPU та Memory працюють по-різному залежно від налаштованої області дії менеджера топології.

Область дії pod менеджера топології та ресурси на рівні Podʼів

Коли область дії менеджера топології встановлено в pod, kubelet виконує єдине вирівнювання за NUMA для всього Podʼа на основі бюджету ресурсів, визначеного в .spec.resources.

Отриманий вирівняний за NUMA пул ресурсів потім розділяється:

  1. Ексклюзивні частки: Контейнери, які визначають ресурси Guaranteed (запити, рівні лімітам, як для CPU, так і для памʼяті, а запит CPU є додатним цілим числом), отримують ексклюзивні частки із загального виділення Podʼа.
  2. Спільний пул Podʼа: Решта ресурсів утворює спільний пул для всіх інших контейнерів у Podʼі, які не отримують ексклюзивного виділення. Хоча контейнери в цьому пулі спільно використовують ресурси один з одним, вони суворо ізольовані від ексклюзивних часток і загального спільного пулу вузла.

Зверніть увагу, що коли стандартні init-контейнери завершують виконання, їхні ресурси переходять у повторно використовуваний набір для Podʼа, а не повертаються до пулу ресурсів вузла. Оскільки вони виконуються послідовно, наступні контейнери застосунку можуть повторно використовувати ці ресурси (або для власних ексклюзивних часток, або для спільного пулу).

Це дозволяє розміщувати разом контейнери, які потребують ексклюзивних ресурсів (наприклад, високопродуктивний основний застосунок), з тими, які цього не потребують (наприклад, sidecars для журналювання або моніторингу), — все в межах одного вирівняного за NUMA Podʼа.

Розглянемо контейнери в наступній специфікації Podʼа, де область дії менеджера топології — pod, а Pod має загальний бюджет у 4 CPU. main-app запитує ексклюзивну частку у 2 CPU, тоді як сайдкари спільно використовують решту 2 CPU у спільному пулі Podʼа:

apiVersion: v1
kind: Pod
metadata:
  name: pod-scope-mixed
  annotations:
    kubernetes.io/description: "A pod demonstrating pod-level scope where one container gets exclusive resources and others share the remaining pod resources in a shared pool."
spec:
  # На рівні Podʼа, Pod має запит на CPU, рівний лімітам, і запит на памʼять також
  # рівний лімітам памʼяті. Контейнер main-app відповідає вимогам для класу QoS
  # Guaranteed на рівні контейнера, а sidecar контейнери не вказують жодного
  # запиту на ресурси. У межах масштабу Podʼа kubelet може статично призначити
  # 4 CPU для всього Podʼа, з яких 2 призначені ексклюзивно для контейнера
  # main-app, а решта 2 спільно використовуються sidecar контейнерами.
  resources:
    requests:
      cpu: "4"
      memory: "4Gi"
    limits:
      cpu: "4"
      memory: "4Gi"
  initContainers:
  - name: metrics-sidecar
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей, а не
    # справжнім допоміжним елементом метрик.
    image: registry.k8s.io/pause:3.9
    restartPolicy: Always
  - name: logging-sidecar
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей, а не
    # справжнім агентом ведення журналів.
    image: registry.k8s.io/pause:3.9
    restartPolicy: Always
  containers:
  - name: main-app
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей.
    image: registry.k8s.io/pause:3.9
    resources:
      requests:
        cpu: "2"
        memory: "2Gi"
      limits:
        cpu: "2"
        memory: "2Gi"

Важливі міркування:

Під час використання ресурсів на рівні Podʼів з областю дії pod менеджера топології є кілька важливих міркувань:

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

    Наприклад, наступний Pod запитує бюджет на рівні Podʼа у 4 CPU. main-app потребує ексклюзивних 3 CPU, а metrics-sidecar потребує ексклюзивний 1 CPU. Оскільки у спільному пулі для logging-sidecar не залишається жодного CPU, kubelet відхиляє цей Pod (та сама перевірка застосовується для памʼяті):

    apiVersion: v1
      kind: Pod
      metadata:
        name: empty-shared-pool
        annotations:
          kubernetes.io/description: "A pod demonstrating a configuration that is rejected because exclusive containers consume the entire pod resource budget, leaving no resources for the remaining container in the shared pool."
      spec:
        # На рівні Podʼа, Pod має запит на CPU, рівний лімітам, і запит на памʼять також
        # рівний лімітам памʼяті. Контейнер main-app і metrics-sidecar відповідають вимогам для
        # класу QoS Guaranteed на рівні контейнера, а контейнер logging-sidecar не вказує
        # жодного запиту на ресурси. Оскільки контейнери Guaranteed споживають весь ресурсний
        # бюджет Podʼа, залишаючи 0 CPU для спільного пулу, необхідного для logging-sidecar,
        # цей Pod буде відхилено при допуску.
        resources:
          requests:
            cpu: "4"
            memory: "4Gi"
          limits:
            cpu: "4"
            memory: "4Gi"
        initContainers:
        - name: metrics-sidecar
          # Примітка: Тут поле image є заповнювачем для демонстраційних цілей, а не
          # справжнім допоміжним елементом метрик.
          image: registry.k8s.io/pause:3.9
          restartPolicy: Always
          resources:
            requests:
              cpu: "1"
              memory: "1Gi"
            limits:
              cpu: "1"
              memory: "1Gi"
        - name: logging-sidecar
          # Примітка: Тут поле image є заповнювачем для демонстраційних цілей, а не
          # справжнім агентом ведення журналів.
          image: registry.k8s.io/pause:3.9
          restartPolicy: Always
        containers:
        - name: main-app
          # Примітка: Тут поле image є заповнювачем для демонстраційних цілей.
          image: registry.k8s.io/pause:3.9
          resources:
            requests:
              cpu: "3"
              memory: "3Gi"
            limits:
              cpu: "3"
              memory: "3Gi"
      
  • Втрачені ресурси: Будь-які ресурси, надмірно виділені під час використання області дії pod (сума запитів контейнерів менша за бюджет на рівні Podʼа, і немає контейнерів спільного пулу, або контейнери спільного пулу не повністю використовують решту), залишаються призначеними та зарезервованими для Podʼа, фактично марнуючись протягом усього виконання Podʼа.

  • Постійний пул: Загальний пул ресурсів Podʼа (вирівнювання за NUMA та загальна зарезервована ємність) є постійним. Якщо контейнер спільного пулу аварійно завершується та перезапускається, загальне резервування ресурсів Podʼа залишається надійно закріпленим на вузлі. Вузол повертає ресурси до свого загального пулу лише тоді, коли завершується весь Pod.

Область дії container менеджера топології та ресурси на рівні Podʼів

Коли область дії менеджера топології встановлено в container, kubelet оцінює кожен контейнер окремо для ексклюзивного виділення.

Якщо весь Pod досягає класу QoS клас QoS Guaranteed (шляхом зазначення відповідних значень у .spec.resources на рівні Podʼа), ви можете змішувати та поєднувати контейнери:

  • Контейнери з власними запитами Guaranteed отримують ексклюзивні, вирівняні за NUMA ресурси.
  • Інші контейнери в Podʼі, які не визначають запити Guaranteed, працюють у спільному пулі вузла.
  • Сукупне споживання ресурсів усіма контейнерами все одно обмежується лімітами .spec.resources Podʼа.

Ця область дії корисна, коли у вас є інфраструктурний sidecar, який має бути вирівняний за конкретним вузлом NUMA для доступу до пристроїв, тоді як основне робоче навантаження може працювати в загальному спільному пулі вузла.

Розглянемо контейнери в наступній специфікації Podʼа, де область дії менеджера топології — container, а Pod представляє робоче навантаження з інфраструктурним sidecar і двома робочими процесами застосунку, із загальним бюджетом у 4 CPU. infrastructure-sidecar отримує ексклюзивну, вирівняну за NUMA частку у 2 CPU. Два робочі процеси застосунку (worker-1 та worker-2) працюють у загальному спільному пулі вузла:

apiVersion: v1
kind: Pod
metadata:
  name: container-scope-mixed
  annotations:
    kubernetes.io/description: "A pod demonstrating container-level scope where one container gets exclusive resources and others run in the node's shared pool."
spec:
  # На рівні Podʼа, Pod має запит на CPU, рівний лімітам, і запит на памʼять також
  # рівний лімітам памʼяті. Контейнер infrastructure-sidecar відповідає вимогам для
  # класу QoS Guaranteed на рівні контейнера, а робочі контейнери не вказують
  # жодного запиту на ресурси. У межах контейнерного масштабу kubelet оцінює
  # контейнери індивідуально для ексклюзивного виділення. Це означає, що
  # infrastructure-sidecar отримує ексклюзивний фрагмент CPU на 2 ядра, тоді як
  # робочі контейнери працюють у загальному пулі вузла, все це обмежено загальними
  # лімітами Podʼа.
  resources:
    requests:
      cpu: "4"
      memory: "4Gi"
    limits:
      cpu: "4"
      memory: "4Gi"
  initContainers:
  - name: infrastructure-sidecar
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей, а не
    # справжнім допоміжним елементом інфраструктури.
    image: registry.k8s.io/pause:3.9
    restartPolicy: Always
    resources:
      requests:
        cpu: "2"
        memory: "2Gi"
      limits:
        cpu: "2"
        memory: "2Gi"
  containers:
  - name: worker-1
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей.
    image: registry.k8s.io/pause:3.9
  - name: worker-2
    # Примітка: Тут поле image є заповнювачем для демонстраційних цілей.
    image: registry.k8s.io/pause:3.9

Квота CPU (CFS)

Під час виконання змішаних робочих навантажень у межах Podʼа kubelet забезпечує ізоляцію по-різному залежно від виділення:

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

Постійний пул і перезапуски

Загальний пул ресурсів Podʼа (вирівнювання за NUMA та загальна зарезервована ємність) є постійним. Якщо контейнер у спільному пулі Podʼа аварійно завершується та перезапускається, загальне резервування ресурсів Podʼа залишається надійно закріпленим на вузлі. Вузол повертає ресурси до свого загального пулу лише тоді, коли завершується весь Pod.

Пониження версії kubelet та контрольні точки стану

У Kubernetes 1.36 увімкнення PodLevelResourceManagers оновило внутрішні файли контрольних точок стану kubelet (cpu_manager_state та memory_manager_state) до формату, який старіші версії kubelet не можуть завантажити. Якщо ви понизите версію kubelet 1.36 після активного використання, старіший kubelet не зможе запуститися; ви маєте очистити вузол, видалити ці файли контрольних точок і перезапустити kubelet.

У Kubernetes 1.37 файли контрольних точок використовують формат, сумісний із майбутніми версіями, щоб запобігти збоям під час запуску при пониженні версії, хоча версії kubelet 1.36 не відновлюють активні призначення ресурсів на рівні Podʼів. Повні деталі про формати контрольних точок і відновлення див. у Довідці менеджерів ресурсів на рівні Podʼів.

Спостережуваність і метрики

Ви можете контролювати поведінку та справність менеджерів ресурсів як для виділень на рівні контейнерів, так і на рівні Podʼів, використовуючи наступні метрики kubelet (увімкнені через функціональну можливість PodLevelResourceManagers):

  • resource_manager_allocations_total: підраховує загальну кількість ексклюзивних виділень ресурсів, виконаних менеджером. Мітка source ("pod" або "node") розрізняє виділення з пулу на рівні вузла та попередньо виділеного пулу на рівні Podʼа.
  • resource_manager_allocation_errors_total: підраховує помилки, що виникають під час ексклюзивного виділення ресурсів, розрізняючи їх за передбачуваним джерелом source виділення ("pod" або "node").
  • resource_manager_container_assignments: відстежує сукупну кількість контейнерів, яким буде надано конкретний тип призначення ресурсів. Мітка assignment_type ("node_exclusive", "pod_exclusive", "pod_shared") забезпечує видимість того, скільки контейнерів працюють з ексклюзивними ресурсами (з пулу вузла або Podʼа) порівняно зі спільним пулом на рівні Podʼа.

PodResources API

У Kubernetes 1.37 локальний для вузла gRPC API PodResources kubelet включає виділення ресурсів на рівні Podʼів, коли увімкнено PodLevelResourceManagers. Локальні для вузла агенти моніторингу та втулки пристроїв можуть запитувати призначення верхнього рівня для Podʼів (cpu_ids та memory), уникаючи подвійного підрахунку виділень на рівні контейнерів.

Повні схеми API, маски полів і таблиці звітування за областями дії див. у Довідці менеджерів ресурсів на рівні Podʼів.

Обмеження та застереження

  • Функціональність реалізована лише для політики static менеджера CPU та політики Static менеджера памʼяті. Зверніть увагу, що політика BestEffort не підтримується для менеджера памʼяті.
  • Ця функція підтримується лише на вузлах Linux. На вузлах Windows менеджери ресурсів діятимуть як no-op для виділень на рівні Podʼів.

Що далі