Перейти до вмісту

Модуль 3.8: AI/ML на хмарно-нативній інфраструктурі

Складність: [СЕРЕДНЯ] — хмарно-нативна архітектура та проєктування робочих навантажень

Час на проходження: 35–45 хвилин

Передумови: Модуль 3.1 (Принципи хмарно-нативних систем), Модуль 3.3 (Хмарно-нативні патерни), базове знайомство з Pod’ами, Деплойментами, Job’ами та плануванням

Що ви зможете зробити

Розділ «Що ви зможете зробити»

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

  1. Застосовувати концепції ресурсів і планування Kubernetes для вибору відповідних патернів виконання для робочих навантажень навчання, донавчання, пакетного інференсу та інференсу в реальному часі.
  2. Порівнювати компоненти Kubernetes із підтримкою GPU, такі як плагіни пристроїв (device plugins), мітки вузлів, taint’и, автомасштабування та спеціалізовані планувальники, у реалістичних сценаріях проєктування платформи.
  3. Проєктувати базову хмарно-нативну архітектуру обслуговування для ендпоінта моделі, що збалансовує приватність, затримку, поведінку масштабування та операційну відповідальність.
  4. Діагностувати типові збої планування AI/ML, читаючи статус Pod’а, події планувальника, ємність вузлів та запити ресурсів прискорювача.
  5. Оцінювати інструменти екосистеми, такі як Kubeflow, KServe, Ray, vLLM, GPU Operator та Volcano, зіставляючи кожен інструмент із конкретною проблемою життєвого циклу, питанням оцінювання або практичним завданням з діагностики, замість того щоб ставитися до кожного робочого навантаження моделі як до звичайного вебсервісу.

Чому цей модуль важливий

Розділ «Чому цей модуль важливий»

Роздрібна компанія запустила функцію рекомендацій, яка ідеально працювала під час невеликого пілоту, а потім дала збій під час сплеску святкового трафіку. Pod’и застосунку масштабувалися, фронтенд залишався справним, а база даних мала запас потужності, проте ендпоінт рекомендацій став повільним, а згодом — недоступним. Платформенна команда зрештою знайшла справжню проблему: серверу моделі потрібні були GPU, автомасштабувальник кластера додавав лише CPU-вузли, і половина реплік інференсу зависла в стані Pending, поки користувачі чекали на пропозиції товарів, які так і не з’явилися.

Такий збій трапляється часто, тому що AI/ML робочі навантаження здалеку виглядають знайомо, але під навантаженням поводяться інакше. Вони все ще працюють у контейнерах, їм усе ще потрібна мережа, і вони все ще отримують вигоду від контролерів Kubernetes, але їхніми найдорожчими ресурсами є прискорювачі та пам’ять, а не звичайний CPU. Той, хто навчається і ставиться до обслуговування моделі як до звичайного безстанового API, пропустить обмеження планування, час запуску, ємність GPU, розмір моделі та поведінку затримки — а саме це визначає, чи працюватиме система.

KCNA не очікує, що ви станете інженером з машинного навчання або встановите кожен інструмент в екосистемі. Він очікує, що ви зможете міркувати про те, чому Kubernetes використовують для AI/ML, як прискорювачі стають планованими ресурсами, чому навчанню та інференсу потрібні різні патерни робочих навантажень, і як хмарно-нативні практики застосовуються до систем, що можуть коштувати більше за годину, ніж решта кластера разом узята. Цей модуль вибудовує таке міркування крок за кроком, починаючи з платформенної проблеми і завершуючи практичним дослідженням планувальника.

Практичний урок полягає в тому, що AI/ML інфраструктура дає збій на межі між мисленням застосунку та мисленням платформи. Розробник моделі може справедливо стверджувати, що коду потрібен GPU, тоді як планувальник бачить лише Pod, який запитує розширений ресурс, набір міток вузла, можливий taint і чергу інших робочих навантажень, що конкурують за ємність. Корисний платформенний інженер перекладає між цими поглядами, не вдаючи, що модель — це магія. Саме тому цей модуль приділяє стільки ж часу формі робочого навантаження, безпеці розгортання та діагностиці на основі доказів, скільки й самій назві прискорювача.

1. Kubernetes корисний для AI/ML, бо координує дефіцитну інфраструктуру

Розділ «1. Kubernetes корисний для AI/ML, бо координує дефіцитну інфраструктуру»

Kubernetes став популярним для AI/ML не тому, що розуміє нейронні мережі. Він став корисним, бо AI/ML платформам потрібне повторюване планування, ізоляція, контроль розгортань, спостережуваність, керування секретами, інтеграція зі сховищем та API, які можуть розділяти багато команд. Це хмарно-нативні платформенні питання, і Kubernetes уже надає для них площину управління.

Важливе зрушення полягає в тому, що AI/ML робочі навантаження часто дбають про ресурси, якими Kubernetes початково не керував. Веб-API може потребувати невеликого обсягу CPU та пам’яті на будь-якому вузлі загального призначення. Завдання навчання моделі може потребувати кількох GPU, великого локального дискового простору для тимчасових даних, високопродуктивного сховища та воркерів, які запускаються разом. Сервер моделі може потребувати одного GPU, достатнього обсягу VRAM для завантаження моделі та політик автомасштабування, прив’язаних до затримки запиту або глибини черги, а не лише до CPU.

┌─────────────────────────────────────────────────────────────┐
│ WHY K8S FOR AI/ML? │
├─────────────────────────────────────────────────────────────┤
│ │
│ Kubernetes provides what AI/ML workloads need: │
│ │
│ 1. GPU SCHEDULING │
│ ───────────────────────────────────────────────────── │
│ K8s schedules GPUs like CPU/memory after a device │
│ plugin advertises accelerator capacity to each kubelet │
│ │
│ 2. DEVICE PLUGINS │
│ ───────────────────────────────────────────────────── │
│ Extend K8s to manage specialized hardware: │
│ • NVIDIA GPUs exposed as nvidia.com/gpu │
│ • AMD GPUs, Intel accelerators, Google TPUs │
│ • Any accelerator integrated through the plugin model │
│ │
│ 3. BATCH PROCESSING │
│ ───────────────────────────────────────────────────── │
│ Jobs and training operators handle runs that finish, │
│ unlike services that are expected to run continuously │
│ │
│ 4. AUTOSCALING │
│ ───────────────────────────────────────────────────── │
│ Scale inference endpoints with traffic, queue length, │
│ latency, or custom metrics when capacity exists │
│ │
└─────────────────────────────────────────────────────────────┘

Корисна ментальна модель — розділити Kubernetes на два рівні. Базова платформа вміє запускати Pod’и, розміщувати їх на вузлах, спостерігати за їхнім статусом та узгоджувати бажаний стан. AI/ML розширення навчають платформу спеціалізованому обладнанню, розподіленому навчанню, обслуговуванню моделей та робочим процесам експериментів. Коли Pod запитує GPU, Kubernetes не запускає алгоритм машинного навчання; він зіставляє запит ресурсу з ємністю вузла, опублікованою плагіном пристрою.

Зупиніться та передбачте: Кластер має три CPU-вузли та один GPU-вузол. Pod запитує nvidia.com/gpu: 1, але не містить жодного селектора вузлів чи affinity. Якщо плагін пристрою NVIDIA встановлено лише на GPU-вузлі, де планувальник може розмістити Pod, і якого статусу слід очікувати, якщо цей GPU вже виділено?

Відповідь полягає в тому, що Pod може працювати лише там, де доступний запитуваний розширений ресурс. Якщо GPU вже виділено, Pod залишається в стані Pending, оскільки ресурси GPU є нестисливими. CPU іноді можна перевиділити та регулювати, але Pod, який запитує цілочисловий GPU, або отримує пристрій, або не запускається.

Ця властивість нестисливості змінює спосіб оцінки ємності. Деплоймент із інтенсивним використанням CPU може ледь жевріти, поки його регулюють, що дає оператору час додати вузли або налаштувати запити. Репліка інференсу, прив’язана до GPU, яка не може отримати пристрій, не стає повільнішою реплікою; вона взагалі не запускається, і Сервіс не має додаткового ендпоінта для прийому трафіку. Ця відмінність особливо важлива під час автомасштабування, оскільки HPA може створювати нові Pod’и швидше, ніж кластер встигає створити вузли з прискорювачами, завантажити драйвери, запустити плагін пристрою, витягнути великий образ моделі та прогріти сервер моделі.

Тому хмарно-нативним AI/ML платформам потрібна історія про ємність раніше, ніж історія про інструменти. Команда має знати, яким просторам імен дозволено споживати прискорювачі, які групи вузлів містять які моделі GPU, чи може продакшн-інференс витісняти експериментальне навчання, і які метрики доводять, що ендпоінт моделі справний. Kubernetes дає вам словник для цих рішень, але не визначає бізнес-пріоритет. Якщо дорогий пул вузлів спільно використовують дослідники, ноутбуки (notebooks), завдання пакетного оцінювання та інференс, орієнтований на клієнтів, то політика є частиною архітектури, а не документом з управління, який хтось читає вже після аварії.

2. Як GPU стають планованими ресурсами Kubernetes

Розділ «2. Як GPU стають планованими ресурсами Kubernetes»

Kubernetes не виявляє автоматично кожен прискорювач у дата-центрі. Kubelet отримує ємність прискорювача від плагіна пристрою, і цей плагін зазвичай працює як DaemonSet на вузлах, де є обладнання. Плагін пристрою повідомляє про ресурси, такі як nvidia.com/gpu, і статус вузла тоді включає цей ресурс як виділювану ємність.

Pod запитує GPU у полі resources.limits. Розширені ресурси запитуються у лімітах як цілі одиниці, і для багатьох типових конфігурацій GPU запит і ліміт фактично є тим самим сигналом планування. Планувальник тоді перевіряє виділювану ємність вузла та наявні виділення, перш ніж прив’язати Pod до вузла.

apiVersion: v1
kind: Pod
metadata:
name: gpu-smoke-test
spec:
restartPolicy: Never
containers:
- name: cuda-container
image: nvidia/cuda:12.4.1-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1

Цей маніфест навмисно невеликий, тому що важливий урок — це запит ресурсу, а не застосунок. Якщо в кластері є GPU-вузол, плагін пристрою справний, а GPU вільний, Pod може запуститися та виконати nvidia-smi. Якщо будь-яке з цих припущень хибне, Kubernetes не вигадає GPU; Pod залишається в стані Pending, а подія планувальника пояснює, якого ресурсу бракує.

КонцепціяЩо це означаєЧому це важливо на практиці
Плагін пристрою (Device Plugin)Компонент рівня вузла, що зазвичай розгортається як DaemonSet, який повідомляє kubelet про пристрої-прискорювачі.Без нього Kubernetes зазвичай бачить звичайні CPU та пам’ять, але не бачить ресурсу GPU для планування.
nvidia.com/gpuПоширена назва розширеного ресурсу, що використовується плагінами GPU NVIDIA.Pod’и запитують цю назву, тож друкарська помилка або відсутній плагін призводить до Pod’ів у стані Pending, а не до повільнішого виконання.
Розподіл часу GPU (GPU time-slicing)Конфігурація, що дозволяє кільком Pod’ам спільно використовувати один фізичний GPU в часі.Це може покращити утилізацію для легких навантажень, але послаблює ізоляцію та може зашкодити передбачуваності затримки.
MIGРозбиття GPU на кілька екземплярів (Multi-Instance GPU) на підтримуваному обладнанні NVIDIA, що надає апаратно ізольовані частки GPU.Це дає сильнішу ізоляцію, ніж розподіл часу, для відповідних навантажень, але потребує сумісного обладнання та планування.
Виділення цілого GPUОдин Pod отримує ексклюзивний доступ до повного фізичного GPU.Це найпростіша модель, що часто є найкращою для важкого навчання або чутливого до затримки інференсу.

Мітки та taint’и вузлів часто з’являються поруч із ресурсами GPU. Мітки допомагають спрямовувати робочі навантаження на конкретні групи вузлів, наприклад на вузли з певною моделлю GPU. Taint’и допомагають тримати звичайні навантаження подалі від дорогих вузлів із прискорювачами, якщо тільки ці навантаження явно не толерують taint. Сам запит ресурсу GPU усе ж є важливим, бо мітка лише каже «запусти на цьому типі вузла», тоді як nvidia.com/gpu: 1 каже «виділи один пристрій цьому контейнеру».

apiVersion: apps/v1
kind: Deployment
metadata:
name: recommender-inference
spec:
replicas: 2
selector:
matchLabels:
app: recommender-inference
template:
metadata:
labels:
app: recommender-inference
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: "accelerator"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
containers:
- name: model-server
image: ghcr.io/example/recommender:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
nvidia.com/gpu: 1
memory: 16Gi

Зверніть увагу на розділення відповідальностей у цьому Деплойменті. nodeSelector і toleration спрямовують Pod до групи GPU-вузлів, тоді як ліміт GPU резервує прискорювач. Запити CPU та пам’яті повідомляють планувальнику, скільки звичайної ємності потрібно Pod’у, а ліміт пам’яті не дає одному серверу моделі вичерпати ресурси вузла. Саме такого комбінованого міркування очікує KCNA: не просто назвати функцію, а застосувати кілька платформенних механізмів разом.

Запит ресурсу також стає операційним контрактом між командою застосунку та платформенною командою. Якщо платформа надає цілі GPU, застосунок запитує цілі GPU і сплачує вартість планування за ексклюзивне виділення. Якщо платформа надає частки MIG або ресурси з розподілом часу, застосунок може запитувати менші повідомлені ресурси, але команда має розуміти компроміс між ізоляцією та продуктивністю. Маніфест, що каже nvidia.com/gpu: 1, — це не просто синтаксис; це твердження про обладнання, облік і поведінку при збоях.

Бойова історія: одна команда якось перенесла прототип класифікатора зображень з єдиного вузла розробки до спільного кластера і зберегла той самий nodeSelector, але випадково прибрала ліміт GPU під час рефакторингу chart’а. Pod усе одно потрапив на GPU-вузол, бо селектор збігся, тож розгортання виглядало правильним під час швидкого огляду. Під навантаженням контейнер дав збій, коли середовище виконання моделі не змогло знайти призначений пристрій, а звичайні CPU-навантаження також почали потрапляти на дорогий вузол, бо політика taint’ів була неузгодженою. Виправленням була не одна магічна мітка; виправленням було зробити так, щоб селектори, taint’и, toleration’и та запити розширених ресурсів розповідали одну й ту саму історію.

3. Навчання, донавчання, пакетний інференс та інференс у реальному часі — це різні робочі навантаження

Розділ «3. Навчання, донавчання, пакетний інференс та інференс у реальному часі — це різні робочі навантаження»

Найбільша помилка новачка — називати кожен контейнер, пов’язаний з моделлю, «AI», а потім розгортати їх однаково. Архітектура Kubernetes починається з форми робочого навантаження. Чи процес завершується, чи працює вічно? Чи потрібні йому всі воркери одночасно? Чи обслуговує він користувачів синхронно? Чи потрібен йому один GPU, багато GPU або жодного GPU після попередньої обробки?

┌─────────────────────────────────────────────────────────────┐
│ AI/ML WORKLOAD TYPES │
├─────────────────────────────────────────────────────────────┤
│ │
│ TRAINING │
│ ───────────────────────────────────────────────────────── │
│ • Runs for hours, days, or sometimes longer │
│ • May need many GPUs distributed across nodes │
│ • Batch workload that should complete successfully │
│ • Distributed runs may need gang scheduling │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌──────────┐ │
│ │ GPU worker │ │ GPU worker │ │ GPU worker │ │ GPU lead │ │
│ │ node A │ │ node A │ │ node B │ │ node B │ │
│ └────────────┘ └────────────┘ └────────────┘ └──────────┘ │
│ │
│ INFERENCE SERVING │
│ ───────────────────────────────────────────────────────── │
│ • Runs continuously and serves predictions │
│ • Latency-sensitive because users or applications wait │
│ • Often scales by adding replicas behind a Service │
│ • May use one GPU per replica or partitioned GPU capacity │
│ │
│ Request ──▶ [Model Server] ──▶ Prediction │
│ [Model Server] Autoscaled replicas │
│ [Model Server] │
│ │
│ FINE-TUNING │
│ ───────────────────────────────────────────────────────── │
│ • Starts from a pretrained model and adapts it to data │
│ • Usually shorter than full training │
│ • Still sensitive to checkpointing, storage, and GPUs │
│ │
└─────────────────────────────────────────────────────────────┘

Навчання — це зазвичай пакетна задача. Команда з науки про дані запускає прогін, чекає на його завершення та очікує отримати артефакти, такі як ваги моделі, метрики або контрольні точки (checkpoints). Job’и Kubernetes підходять для простого навчання, бо вони відстежують завершення та не перезапускають успішні Pod’и нескінченно. Більші команди можуть використовувати оператори навчання, такі як PyTorchJob або TFJob, бо ці оператори розуміють ролі воркерів, поведінку розподіленого запуску та події життєвого циклу, специфічні для навчання.

Інференс у реальному часі — це зазвичай сервісна задача. Ендпоінт моделі приймає запити, повертає передбачення та має залишатися доступним, поки трафік змінюється. Деплойменти, Сервіси, автомасштабувальники та стратегії розгортання підходять для цієї форми, бо репліки можна замінювати поступово, а трафік можна спрямовувати геть від несправних Pod’ів. Інференс також має особливі обмеження: запуск моделі може займати хвилини, пам’ять GPU може бути обмежувальним чинником, а утилізація CPU може не відображати справжнє вузьке місце.

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

АспектНавчанняДонавчанняПакетний інференсІнференс у реальному часі
ТривалістьТривале, але скінченне, часто години чи дні.Скінченне і зазвичай коротше за повне навчання.Скінченне, прив’язане до набору даних чи черги.Безперервне, обслуговує, поки продукту потрібні передбачення.
Патерн KubernetesJob, оператор навчання чи пакетний планувальник.Job чи спеціалізований оператор.Job, робочий процес чи воркери на основі черги.Деплоймент, Сервіс, автомасштабувальник та контролі розгортання.
Питання масштабуванняПропускна здатність, паралельні воркери та перезапуск із контрольної точки.Вартість GPU, доступ до сховища та відтворюваність.Пропускна здатність набору даних та відновлення після збою.Затримка, конкурентність, готовність та сплески трафіку.
Обробка збоївВідновлення з контрольних точок або перезапуск невдалого прогону.Збереження проміжних адаптерів чи контрольних точок.Повторна спроба невдалих частин без дублювання результату.Маршрутизація навколо несправних реплік та безпечне розгортання.
Ризик плануванняЧасткове розміщення воркерів може марнувати GPU.Кілька GPU можуть блокувати інші команди, якщо пріоритети неясні.Великі черги можуть голодом виснажити інтерактивні навантаження.Репліки можуть запускатися надто повільно для раптового трафіку.

Зупиніться та вирішіть: Ваша команда має скрипт, який читає вчорашні тікети підтримки, класифікує кожен тікет за допомогою наявної моделі, записує мітки до бази даних і завершується. Чи запустили б ви його як Деплоймент, Job чи DaemonSet? Запишіть, яку поведінку Kubernetes вам потрібно, перш ніж обирати ресурс.

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

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

Донавчання заслуговує на власне судження, бо часто здається достатньо маленьким, щоб імпровізувати, але водночас достатньо дорогим, щоб спричинити напругу на платформі. Команда, яка адаптує попередньо навчену модель, може потребувати менше GPU, ніж повний прогін навчання, але їй усе одно потрібна відтворюваність, доступ до набору даних, створення контрольних точок і чітке володіння вихідними артефактами. Якщо кожне донавчання запускається вручну з привілейованого ноутбука, організація матиме труднощі з відповіддю на питання, які дані було використано, який образ створив ваги, і чи можна відтворити результат. Job’и Kubernetes, системи робочих процесів або оператори навчання — це не бюрократія в такій ситуації; це аудиторський слід, який робить корисний експеримент придатним для просування.

4. Розподіленому навчанню потрібні гарантії планування, яких типовий Kubernetes може не надати

Розділ «4. Розподіленому навчанню потрібні гарантії планування, яких типовий Kubernetes може не надати»

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

Групове планування (gang scheduling) вирішує цю проблему, розглядаючи набір Pod’ів як єдине ціле. Планувальник допускає групу лише тоді, коли існує достатньо ресурсів для всієї групи, або чекає, не прив’язуючи часткових воркерів. Інструменти на кшталт Volcano додають можливості пакетного планування, зокрема групове планування, черги та справедливий розподіл. KCNA не вимагає глибокого знання конфігурації, але очікує, що ви розпізнаєте, чому поведінка типового планувальника «один Pod за раз» може погано підходити для розподілених AI/ML завдань.

┌─────────────────────────────────────────────────────────────┐
│ DEFAULT SCHEDULING VS. GANG SCHEDULING │
├─────────────────────────────────────────────────────────────┤
│ │
│ Default scheduler: │
│ │
│ worker-1 ──▶ scheduled ──▶ holds GPU │
│ worker-2 ──▶ scheduled ──▶ holds GPU │
│ worker-3 ──▶ Pending ──▶ no GPU left │
│ worker-4 ──▶ Pending ──▶ no GPU left │
│ │
│ Result: partial job may hold GPUs while doing no work │
│ │
│ Gang scheduler: │
│ │
│ workers 1-4 ──▶ enough GPUs? ──▶ yes: schedule all │
│ │ │
│ └────▶ no: schedule none yet │
│ │
│ Result: fewer stranded GPUs and clearer queue behavior │
│ │
└─────────────────────────────────────────────────────────────┘

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

Пріоритети та квоти мають значення, бо GPU-кластери є спільними. Дослідницький ноутбук, продакшн-ендпоінт інференсу та прогін навчання не повинні всі конкурувати без політики. ResourceQuota, PriorityClass, системи черг та окремі пули вузлів — це способи виразити бізнес-намір. Платформа має відповісти на питання на кшталт «Чи може експеримент витіснити продакшн-інференс?» та «Скільки GPU може спожити один простір імен?», перш ніж сплеск трафіку або дедлайн навчання змусять до цього вдатися.

Типове планування все ще цінне, і річ не в тому, що кожному AI/ML навантаженню потрібен власний планувальник. Однореплічний ендпоінт моделі, невеликий Job пакетного оцінювання або стадія попередньої обробки лише на CPU можуть чудово працювати зі звичайним плануванням Kubernetes. Архітектурна навичка — розпізнати, коли незалежне розміщення Pod’ів стає хибною абстракцією. Якщо корисною одиницею роботи є «всі воркери в цій групі навчання», то допуск до черги має відбуватися на рівні цієї одиниці. Якщо корисною одиницею є «один незалежний оцінювач на шард даних», звичайного паралелізму Job’а може бути достатньо.

Сховище може бути прихованим обмеженням після того, як планування вже вдалося. Завдання навчання, яке запускає всіх воркерів, але читає набір даних на кілька терабайтів через перевантажений мережевий шлях, може марнувати години GPU, чекаючи на дані. Завдання пакетного інференсу, яке записує результати без ідемпотентності, може створити дубльовані рядки після повторних спроб. Сервер моделі, який завантажує ваги з об’єктного сховища при кожному запуску, може створювати повільні розгортання та галасливі збої залежностей. Тому платформенне рішення ширше за «GPU чи не GPU»; воно включає локальність даних, розташування контрольних точок, поведінку перезапуску та чи може навантаження відновитися з перерваного стану.

5. Обслуговування моделей додає компроміси затримки, розгортання та приватності

Розділ «5. Обслуговування моделей додає компроміси затримки, розгортання та приватності»

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

Організації самостійно хостять інференс із кількох причин. Приватність є поширеним мотивом, бо запити, документи, зображення або записи клієнтів можуть бути надто чутливими, щоб надсилати їх до зовнішнього API. Затримка може покращитися, коли сервер моделі розташований близько до застосунку та даних. Вартість може покращитися за стабільно високого обсягу, якщо команда може тримати GPU дуже завантаженими. Контроль покращується, бо організація обирає версії моделей, налаштування квантизації, час розгортання та спостережуваність.

┌─────────────────────────────────────────────────────────────┐
│ WHY SELF-HOST LLMs? │
├─────────────────────────────────────────────────────────────┤
│ │
│ PRIVACY Sensitive data stays in controlled systems │
│ COST Sustained high volume may beat per-token APIs │
│ LATENCY Co-locate model servers with applications │
│ COMPLIANCE Meet data residency and audit requirements │
│ CONTROL Choose model, version, runtime, and rollout │
│ │
│ Trade-off: The platform team owns GPUs, drivers, scaling, │
│ model rollout, capacity planning, and incident response. │
│ │
└─────────────────────────────────────────────────────────────┘

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

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

apiVersion: apps/v1
kind: Deployment
metadata:
name: ticket-classifier
spec:
replicas: 2
selector:
matchLabels:
app: ticket-classifier
template:
metadata:
labels:
app: ticket-classifier
spec:
containers:
- name: classifier
image: ghcr.io/example/ticket-classifier:2.1.0
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 5
failureThreshold: 6
startupProbe:
httpGet:
path: /ready
port: 8080
periodSeconds: 10
failureThreshold: 30
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
memory: 8Gi
nvidia.com/gpu: 1

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

Розгортання — ще одне місце, де звичні звички вебсервісів потребують коригування. Невеликий API часто може запуститися за секунди, швидко приймати трафік і відкочуватися з малими витратами. Великому серверу моделі може знадобитися витягнути гігабайти шарів образу або ваг моделі, виділити пам’ять GPU, скомпілювати ядра (kernels) та прогріти кеші запитів, перш ніж видати перше корисне передбачення. Якщо стратегія Деплойменту дозволяє завершити надто багато старих реплік до того, як нові репліки справді готові, система може втратити обслуговувальну ємність під час звичайного релізу. Гейти готовності (readiness gates), консервативні налаштування надлишку (surge) та чіткі критерії відкату — це частина архітектури обслуговування, а не необов’язковий лиск.

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

Перш ніж запускати це на реальній платформі, який вихід переконав би вас, що ендпоінт моделі готовий для користувачів, а не просто живий як процес? Сильна відповідь називає докази з кількох рівнів: Pod у стані Running, ендпоінт готовності повідомляє про завантажений стан моделі, Сервіс має готові ендпоінти, метрики затримки в межах цілі, пам’ять GPU виділено як очікувалося, а синтетичне передбачення успішне. Цей ланцюжок доказів запобігає поширеному збою, коли оператор бачить зелений Pod і пропускає той факт, що сервер моделі ще прогрівається або відхиляє запити.

6. Інструменти екосистеми вирішують різні частини життєвого циклу AI/ML

Розділ «6. Інструменти екосистеми вирішують різні частини життєвого циклу AI/ML»

Екосистема AI/ML на Kubernetes велика, бо життєвий цикл ширший за «запустити контейнер». Командам потрібні ноутбуки для досліджень, конвеєри для повторюваного навчання, реєстри для версій моделей, системи обслуговування для інференсу, планувальники для пакетних завдань та моніторинг для дрейфу продуктивності. Жоден окремий інструмент не варто обирати лише тому, що він з’являється на архітектурній діаграмі AI/ML.

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

KServe зосереджується на обслуговуванні моделей. Вона надає абстракції для сервісів інференсу, патерни канаркового розгортання (canary rollout), інтеграції автомасштабування та угоди про сервери моделей. vLLM — це рушій інференсу з високою пропускною здатністю, що часто використовується для великих мовних моделей, де пакетна обробка та керування пам’яттю сильно впливають на вартість і затримку. Ray — це фреймворк розподілених обчислень, що використовується для навчання, обробки даних та патернів обслуговування, яким потрібне гнучке розподілене виконання.

ІнструментЩо він робитьНайкращий сценарій застосування
KubeflowНадає Kubernetes-нативну ML-платформу з ноутбуками, конвеєрами, компонентами навчання та інтеграціями обслуговування.Платформенна команда хоче спільне середовище ML-робочих процесів для кількох команд.
KServeСтандартизує обслуговування інференсу моделей на Kubernetes з патернами розгортання та масштабування.Команді потрібні продакшн-ендпоінти моделей, а не лише завдання навчання.
RayЗапускає розподілені Python-навантаження для навчання, обробки даних та обслуговування.Навантаженню потрібне гнучке розподілене виконання за межами одного Pod’а.
vLLMЕфективно обслуговує великі мовні моделі за допомогою оптимізованої пакетної обробки та керування пам’яттю.Організація самостійно хостить інференс LLM і потребує високої пропускної здатності на GPU.
NVIDIA GPU OperatorАвтоматизує налаштування драйвера GPU, середовища виконання контейнерів, моніторингу та плагіна пристрою.Платформенна команда керує пулами GPU-вузлів NVIDIA і хоче повторюваних операцій.
VolcanoДодає можливості пакетного планування, такі як групове планування, черги та справедливий розподіл.Завданням розподіленого навчання потрібно, щоб усі воркери планувалися разом, або потрібна передбачувана поведінка черги.
┌─────────────────────────────────────────────────────────────┐
│ ML PIPELINE ON KUBERNETES │
├─────────────────────────────────────────────────────────────┤
│ │
│ Data Prep ──▶ Training ──▶ Evaluation ──▶ Serving ──▶ Monitor│
│ │ │ │ │ │ │
│ [Spark or [Kubeflow [tests, [KServe, [Prom │
│ Ray jobs] Training] metrics] vLLM] + logs│
│ │
│ Kubernetes provides the API, Pods, Services, controllers, │
│ scheduling hooks, secrets, storage integration, and events. │
│ │
└─────────────────────────────────────────────────────────────┘

Перевірка архітектури: Ваша організація має одну модель шахрайства, яку перенавчають щотижня та обслуговують за внутрішнім API. Команді з науки про дані не потрібні ноутбуки в кластері. Що ймовірніше буде першою корисною інвестицією в платформу: повне встановлення Kubeflow, патерн із невеликого Job’а плюс Деплоймент, чи інструмент, орієнтований на обслуговування, такий як KServe? Обґрунтуйте операційну вартість вашого вибору.

Практична відповідь могла б почати з Job’а для перенавчання та Деплойменту чи ендпоінта інференсу на основі KServe, а потім додати Kubeflow лише тоді, коли повторювані робочі процеси, ноутбуки чи стандартизація для багатьох команд виправдають накладні витрати. Вибір інструменту має слідувати за болем робочого процесу. Встановлення великої платформи до того, як у команди з’явиться проблема життєвого циклу, може створити більше роботи, ніж усуне.

Те саме міркування стосується інструментів операцій GPU. NVIDIA GPU Operator може спростити керування драйвером, середовищем виконання, моніторингом та плагіном пристрою, особливо в кількох пулах вузлів або керованих середовищах із потребами в повторюваному налаштуванні. Він не є заміною розуміння того, що повідомляє плагін пристрою, що бачить планувальник, або як навантаження запитує ресурс. Якщо Pod у стані Pending з Insufficient nvidia.com/gpu, оператор може бути частиною шляху відновлення, але питання діагностики залишається на основі доказів: чи існують вузли, чи повідомляють вони про виділювані ресурси GPU, чи ці ресурси вже виділено, і чи сумісні політики розміщення з Pod’ом?

Обслуговування великих мовних моделей додає ще один вимір, бо вибір середовища виконання впливає на ємність не менше, ніж конфігурація Kubernetes. Рушії на кшталт vLLM покращують пропускну здатність за рахунок стратегій пакетної обробки та керування пам’яттю, але ці оптимізації все одно живуть усередині Pod’а, якому потрібна ємність GPU, поведінка готовності, спостережуваність і контроль розгортання. Команда, яка налаштовує середовище виконання, але ігнорує планування Kubernetes, усе одно може не змасштабуватися. Команда, яка пише ідеальний YAML Kubernetes, але обирає невідповідне середовище виконання для обслуговування, може марнувати години GPU на погану пакетну обробку. Дизайн платформи має поєднувати обидва рівні.

7. Розбір прикладу: Діагностика Деплойменту інференсу GPU у стані Pending

Розділ «7. Розбір прикладу: Діагностика Деплойменту інференсу GPU у стані Pending»

Розбір прикладу показує процес міркування, перш ніж ви спробуєте подібне практичне завдання. У цьому сценарії команда розгортає сервер моделі для інференсу в реальному часі. Деплоймент достатньо коректний, щоб створювати Pod’и, але жодна репліка не переходить у стан Running. Ваша мета — перейти від симптому до причини, використовуючи докази Kubernetes, а не здогадки.

Команда застосовує цей Деплоймент до кластера розробки. Вони очікують, що одна репліка запуститься, бо вважають, що кластер має GPU-вузол. Платформа використовує поширений псевдонім k для kubectl; після одноразового визначення псевдоніма за допомогою alias k=kubectl команди нижче використовують k для стислості.

apiVersion: apps/v1
kind: Deployment
metadata:
name: image-ranker
spec:
replicas: 1
selector:
matchLabels:
app: image-ranker
template:
metadata:
labels:
app: image-ranker
spec:
containers:
- name: ranker
image: ghcr.io/example/image-ranker:1.0.0
ports:
- containerPort: 8080
resources:
requests:
cpu: "1"
memory: 4Gi
limits:
memory: 8Gi
nvidia.com/gpu: 1

Крок 1: Почніть із контролера, потім огляньте Pod

Розділ «Крок 1: Почніть із контролера, потім огляньте Pod»

Новачок часто починає з негайної зміни YAML, але сильніша звичка — оглянути те, що Kubernetes створив. Деплоймент володіє ReplicaSet’ом, а ReplicaSet володіє Pod’ами. Якщо в Деплоймента є недоступні репліки, спершу огляньте контролер, а потім переходьте до статусу Pod’а та подій планувальника.

Terminal window
k get deployment image-ranker
k get pods -l app=image-ranker

Вихід нижче показує справний об’єкт контролера без доступної репліки, бо єдиний створений Pod усе ще в стані Pending.

NAME READY UP-TO-DATE AVAILABLE AGE
image-ranker 0/1 1 0 2m
NAME READY STATUS RESTARTS AGE
image-ranker-6c9d7f8d9b-hp2lm 0/1 Pending 0 2m

Pending означає, що контейнер не запустився. Це відрізняється від CrashLoopBackOff, де Pod було заплановано, контейнер запустився, але дав збій. Для проблем планування вихід describe pod є головним джерелом істини, бо він містить події планувальника. У цьому сценарії подія прямо називає відсутній розширений ресурс.

Terminal window
k describe pod -l app=image-ranker

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

Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 2m default-scheduler 0/4 nodes are available: 4 Insufficient nvidia.com/gpu.

Крок 2: Інтерпретуйте подію замість того, щоб запам’ятовувати відповідь

Розділ «Крок 2: Інтерпретуйте подію замість того, щоб запам’ятовувати відповідь»

Планувальник каже, що не може знайти достатньо ємності nvidia.com/gpu. Це не доводить, що в кластері немає фізичного GPU. Це доводить, що планувальник Kubernetes наразі не бачить вільної виділюваної ємності для цього ресурсу. Причиною може бути відсутній плагін пристрою, відсутність GPU-вузлів, спожитий GPU, taint вузла без toleration або node affinity, що виключає потрібний вузол.

Наступна команда перевіряє, чи хоч якийсь вузол повідомляє про ємність GPU. Якщо жоден вузол не показує nvidia.com/gpu серед виділюваних ресурсів, проблема лежить нижче за маніфест навантаження. Платформенній команді потрібно підтвердити GPU-вузли, драйвери та плагін пристрою. Справний GPU-вузол містить рядок на кшталт показаного нижче під Allocatable.

Terminal window
k describe nodes | grep -A5 -E "Name:|Allocatable:"
nvidia.com/gpu: 1

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

Крок 3: Перевірте, чи навантаженню не бракує правил розміщення

Розділ «Крок 3: Перевірте, чи навантаженню не бракує правил розміщення»

Припустімо, вузол справді повідомляє про nvidia.com/gpu, але Pod усе ще в стані Pending. Наступне корисне питання — чи має вузол taint’и, що відштовхують звичайні Pod’и. GPU-вузли зазвичай мають taint, бо вони дорогі, і платформенна команда хоче, щоб туди потрапляли лише навантаження, обізнані з GPU. Перевірте політику taint’ів, перш ніж змінювати Деплоймент.

Terminal window
k describe node gpu-node-1 | grep -A4 Taints

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

Taints: accelerator=gpu:NoSchedule

Деплоймент вище запитує GPU, але не толерує taint. Виправлення — додати відповідний toleration, і багато команд також додають селектор вузлів або правило affinity, щоб виразити бажаний пул вузлів.

spec:
template:
spec:
nodeSelector:
accelerator: nvidia
tolerations:
- key: "accelerator"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"

Крок 4: Перевірте виправлений шлях планування

Розділ «Крок 4: Перевірте виправлений шлях планування»

Після оновлення Деплойменту перевірте Pod знову, замість того щоб припускати, що виправлення спрацювало. Успішний результат має перейти з Pending до ContainerCreating, а потім до Running, за умови що витягування образу та запуск моделі вдаються. Якщо він переходить до CrashLoopBackOff, це прогрес у послідовності діагностики, бо проблема змінилася з планування на середовище виконання.

Terminal window
k rollout status deployment/image-ranker
k get pods -l app=image-ranker -o wide
k describe pod -l app=image-ranker

Ключовий урок — порядок дослідження. Почніть зі спостережуваного статусу, прочитайте події планувальника, підтвердьте виділювані ресурси вузла, а потім огляньте обмеження розміщення, такі як taint’и, toleration’и, селектори та affinity. Той самий патерн працює для практичної вправи далі в модулі, навіть коли ваш локальний кластер не має реального GPU-обладнання.

Цей приклад також показує, чому «Pending» — не розпливчастий статус. Він звужує проблему до планування та допуску, перш ніж середовище виконання контейнерів запустить навантаження. Якщо Pod пізніше переходить до ContainerCreating, ви досліджуєте витягування образів, монтування томів, класи середовища виконання (runtime classes) та налаштування на рівні вузла. Якщо він переходить до CrashLoopBackOff, ви досліджуєте команду, середовище, файли моделі, дозволи та логи застосунку. Хороша діагностика Kubernetes — це послідовність звужувальних питань, і GPU-навантаження винагороджують таку дисципліну, бо сліпа зміна маніфестів може приховати справжній сигнал дефіциту.

Патерни та антипатерни

Розділ «Патерни та антипатерни»

Патерни — це повторно використовувані рішення, що роблять дефіцитну ємність прискорювачів передбачуваною. Це не правила для сліпого копіювання, бо правильна відповідь залежить від форми навантаження, вартості обладнання та операційної зрілості команди. В AI/ML платформах найдовговічніші патерни роблять намір видимим і для Kubernetes, і для людей: маніфест каже, що потрібно навантаженню, політика пулу вузлів каже, хто може ним користуватися, а шлях спостережуваності показує, чи спрацювало рішення.

ПатернКоли його застосовуватиЧому він працюєПитання масштабування
Виділені пули вузлів із прискорювачамиПродакшн-інференсу чи дорогому навчанню потрібен передбачуваний доступ до відомих моделей GPU.Мітки, taint’и, квоти та політики автомасштабування можна налаштувати під навантаження з прискорювачами, не порушуючи CPU-сервіси.Тримайте окремі пули для несумісних моделей GPU чи рівнів ізоляції, щоб рішення планування лишалися зрозумілими.
Скінченна робота як Job’и чи робочі процесиНавчання, донавчання та пакетний інференс мають чітку умову завершення.Завершення, повторні спроби, відстрочки та передача артефактів відповідають навантаженню краще, ніж безперервно узгоджувані репліки.Додайте створення контрольних точок та ідемпотентний вихід, щоб повторні спроби не марнували великі прогони чи не дублювали результати.
Ендпоінти обслуговування з готовністю, обізнаною з моделлюІнференс у реальному часі є частиною шляху запиту користувача чи сервісу.Готовність повідомляє про спроможність передбачати, а не про існування процесу, що захищає тих, хто викликає, під час запуску та розгортання.Поєднуйте готовність із метриками затримки, глибини черги та GPU, бо лише CPU може не показувати насичення.
Пакетні планувальники для згрупованих воркерівРозподіленому навчанню потрібно, щоб усі чи більшість воркерів запускалися разом.Групове планування та черги запобігають тому, щоб часткове розміщення утримувало GPU, поки завдання не може просуватися.Визначте пріоритет черги та справедливий розподіл, перш ніж кілька команд почнуть конкурувати за той самий пул прискорювачів.

Антипатерни зазвичай з’являються, коли команда ставиться до AI/ML навантаження або як до чогось цілком особливого, або як до чогось цілком звичайного. Якщо ставитися як до цілком особливого, платформа перетворюється на купу спеціальних скриптів без повторюваності. Якщо ставитися як до звичайного, команда пропускає планування прискорювачів, поведінку завантаження моделі та відмінності життєвого циклу. Здоровіша золота середина — використовувати примітиви Kubernetes там, де вони підходять, і додавати спеціалізовані контролери лише там, де цього вимагає життєвий цикл моделі.

АнтипатернЩо йде не такКраща альтернатива
Одна гігантська ML-платформа для однієї простої моделіКоманда експлуатує ноутбуки, конвеєри, інтеграції ідентичності та абстракції обслуговування ще до того, як ці проблеми існують.Почніть із Job’а, Деплойменту чи ендпоінта KServe та чіткого сховища артефактів, потім розширюйте, коли повторюваність робочих процесів це виправдає.
GPU-вузли без політики допускуЕксперименти, ноутбуки та продакшн-інференс конкурують за вартістю, а не за пріоритетом, спричиняючи несподівані Pod’и в стані Pending чи галасливі інциденти.Використовуйте taint’и, toleration’и, ResourceQuota, PriorityClass та окремі пули вузлів, щоб закодувати бажану модель спільного використання.
Автомасштабування за хибним сигналомМасштабування за CPU виглядає справним, тоді як пам’ять GPU, черги запитів чи затримка вже насичені.Масштабуйте інференс за метриками, що відображають вузьке місце, та перевірте, що групи вузлів із прискорювачами теж можуть масштабуватися.
Ігнорування шляху артефакту моделіPod’и запускаються повільно чи дають збій під час розгортання, бо кожна репліка завантажує великі ваги з перевантаженого чи недоступного сховища.Розглядайте сховище моделей, кешування, шарування образів та проби запуску як частину дизайну розгортання.

Структура ухвалення рішень

Розділ «Структура ухвалення рішень»

Використовуйте наступну структуру, коли хтось запитує: «Як нам запустити цю модель на Kubernetes?» Перше рішення — чи процес скінченний, чи безперервний, бо це відокремлює навчання та пакетне оцінювання від обслуговування. Друге рішення — чи потрібні навантаженню прискорювачі, бо це вводить плагіни пристроїв, розширені ресурси, пули вузлів та політику вартості. Третє рішення — чи навантаження незалежне, чи згруповане, бо розподілене навчання може потребувати семантики пакетного планування, якої звичайні Деплойменти не надають.

┌─────────────────────────────────────────────────────────────┐
│ AI/ML WORKLOAD DECISION PATH │
├─────────────────────────────────────────────────────────────┤
│ │
│ Does the process finish? │
│ │ │
│ ├── yes ──▶ Training, fine-tuning, or batch inference │
│ │ Use Job, workflow, or training operator │
│ │ │
│ └── no ───▶ Real-time or internal inference service │
│ Use Deployment, Service, probes, scaling │
│ │
│ Does it need accelerators? │
│ │ │
│ ├── yes ──▶ Verify device plugin, GPU resources, │
│ │ taints, tolerations, labels, autoscaling │
│ │ │
│ └── no ───▶ Treat as ordinary CPU/memory workload │
│ but keep artifact and data paths explicit │
│ │
│ Do workers need to start together? │
│ │ │
│ ├── yes ──▶ Consider Volcano or training operators │
│ └── no ───▶ Default scheduler may be sufficient │
│ │
└─────────────────────────────────────────────────────────────┘
Точка рішенняОбирайте це, колиКомпроміс, який треба прийняти
Job чи робочий процесЗадача моделі має чітку умову завершення та видає артефакти чи пакетний вихід.Вам потрібно спроєктувати повторні спроби, створення контрольних точок та ідемпотентність виходу, замість того щоб покладатися на завжди активні репліки.
Деплоймент плюс СервісМодель безперервно відповідає на запити, і тим, хто викликає, потрібен стабільний мережевий доступ.Вам потрібно опрацювати готовність, час розгортання, метрики автомасштабування та прогріту ємність.
KServe чи абстракція обслуговуванняБагатьом командам потрібне узгоджене обслуговування моделей, канарки, угоди про масштабування чи інтеграція сервера моделі.Ви додаєте ще одну поверхню площини управління, яку платформенні інженери мають експлуатувати та діагностувати.
Kubeflow чи ширша ML-платформаОрганізації потрібні спільні ноутбуки, конвеєри, робочі процеси навчання та управління життєвим циклом для багатьох команд.Ви приймаєте складність встановлення, оновлень, інтеграції ідентичності та підтримки користувачів.
Ray чи розподілений фреймворкНавантаженню потрібне гнучке розподілене виконання Python, обробка даних чи патерни обслуговування за межами одного Pod’а.Вам потрібно експлуатувати середовище виконання фреймворку, а також ресурси Kubernetes під ним.
Volcano чи пакетний планувальникЗгруповані воркери, черги, групове планування чи справедливий розподіл є центральними для успіху навантаження.Вам потрібно визначити політику черги та навчити користувачів, чим пакетне планування відрізняється від типового розміщення Pod’ів.

Який підхід ви обрали б для нічного завдання пакетного оцінювання, що сьогодні працює на CPU, але наступного кварталу може потребувати одного GPU, і чому? Практична відповідь могла б почати з Job’а чи робочого процесу зараз, тримати вхід і вихід даних ідемпотентними та уникати встановлення повної ML-платформи, доки не з’являться повторювані потреби в робочому процесі. Майбутня вимога GPU має впливати на те, як ви іменуєте ресурси, ізолюєте простори імен та документуєте шлях планування, але не повинна змушувати команду експлуатувати кожен компонент екосистеми ще до того, як навантаженню це знадобиться.

Є одна остання перевірка, яку досвідчені платформенні команди використовують, перш ніж схвалити AI/ML дизайн: вони запитують, які докази довели б, що дизайн хибний. Якщо завдання навчання не може відновитися з контрольних точок, то один збій вузла може змарнувати весь прогін. Якщо Деплоймент інференсу масштабує репліки, але кластер не може додати GPU-вузли, то автомасштабування створює Pod’и в стані Pending без додавання обслуговувальної ємності. Якщо ендпоінт обслуговування приватний, але вміст запитів з’являється в логах, то аргумент про приватність руйнується, навіть якщо модель ніколи не викликала зовнішній API. Таке мислення перетворює огляд архітектури на перевірювані твердження, а не на вподобання.

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

Для міркування на рівні KCNA важлива звичка — постійно пов’язувати симптоми назад із об’єктами Kubernetes. Повільний ендпоінт моделі може бути проблемою налаштування середовища виконання, але репліки в стані Pending вказують насамперед на планування. Невдалий прогін навчання може бути поганим кодом, але часткове розміщення воркерів вказує насамперед на групування навантаження та політику черги. Питання приватності може стосуватися моделі, але примусова межа з’являється у просторах імен, ідентичностях, мережевих шляхах, виборі логування та призначеннях сховища.

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

  2. Групове планування не є частиною поведінки типового планувальника, з якою більшість новачків стикається першими. Kubernetes зазвичай прив’язує Pod’и незалежно, тож команди розподіленого навчання часто додають планувальники на кшталт Volcano, коли часткове розміщення залишало б GPU без діла та блокувало корисну роботу.

  3. Сервер моделі може бути в стані Running, але все ще не готовий обслуговувати передбачення. Великим моделям може знадобитися час, щоб завантажити ваги, виділити пам’ять GPU, скомпілювати ядра чи прогріти кеші, — саме тому проби готовності та запуску мають значення для надійності інференсу.

  4. Kubernetes виборов роботу з AI/ML інфраструктурою завдяки розширюваності, а не первісному дизайну. Плагіни пристроїв, власні контролери, оператори та спеціалізовані планувальники дають платформі змогу адаптуватися до прискорювачів та ML-робочих процесів, не вимагаючи кожної функції в основному API.

ПомилкаЧому це трапляєтьсяЯк це виправити
Думати, що Kubernetes автоматично виявляє GPU після встановлення.Команди бачать фізичний GPU на вузлі та припускають, що планувальник може його виділити без шляху плагіна пристрою.Встановіть і перевірте плагін пристрою вендора чи GPU Operator, потім підтвердьте, що вузли повідомляють про nvidia.com/gpu як виділювану ємність.
Використовувати Деплоймент для скрипту навчання, який має завершитися.Деплойменти звичні, тож скінченний скрипт загортають у контролер, що очікує безперервних реплік.Використовуйте Job, рушій робочих процесів чи оператор навчання для навчання, донавчання та завдань пакетного інференсу з семантикою завершення.
Покладатися лише на мітки вузлів для GPU-навантажень.Мітка здається контролем розміщення, але вона не виділяє прискорювач і не обходить taint.Поєднуйте ліміти ресурсів, селектори чи affinity та toleration’и, щоб розміщення та резервування пристрою відповідали політиці пулу вузлів.
Масштабувати інференс лише за утилізацією CPU.Узагальнені приклади автомасштабування вебсервісів копіюють, навіть коли вузьким місцем є пам’ять GPU, глибина черги чи затримка.Обирайте сигнали автомасштабування, що відповідають реальному вузькому місцю сервера моделі, та перевірте, що групи GPU-вузлів можуть додавати ємність.
Ігнорувати час завантаження моделі під час розгортань.Процес контейнера запускається до завантаження ваг, тож оператори плутають Running із готовністю.Використовуйте проби запуску та готовності, що відображають реальну готовність обслуговувати модель, та налаштуйте параметри розгортання для прогрітої ємності.
Розглядати розподіл часу GPU як рівноцінний апаратній ізоляції.Цілі утилізації приховують той факт, що спільні GPU можуть створювати ефекти галасливого сусіда та непередбачувану затримку.Використовуйте цілі GPU чи MIG там, де ізоляція має значення, і резервуйте розподіл часу для відповідних навантажень розробки чи легких навантажень.
Встановлювати повну ML-платформу до визначення проблеми робочого процесу.Діаграми інструментів роблять кожен компонент обов’язковим на вигляд ще до того, як у команди з’явиться повторюваний біль життєвого циклу.Почніть із найменшого патерну, що вирішує навантаження, потім впроваджуйте Kubeflow, KServe, Ray чи Volcano, коли їхні абстракції окупляться.
Забувати, що автомасштабування кластера має розуміти групи GPU-вузлів.HPA створює Pod’и, але автомасштабувальник може лише додавати CPU-вузли або не може задовольнити мітки та taint’и прискорювачів.Налаштуйте автомасштабування для пулів вузлів із прискорювачами та перевірте, що події Pending запускають очікуваний шлях масштабування назовні.
1. Ваша команда розгортає модель рекомендацій у реальному часі як Деплоймент із трьома репліками. Під час сплеску трафіку HPA створює більше реплік, але нові Pod'и залишаються в стані Pending з `Insufficient nvidia.com/gpu`. Що слід дослідити першим?

Дослідіть, чи групи GPU-вузлів та плагін пристрою надають достатньо виділюваної ємності прискорювача. Pending означає, що Pod не заплановано, тож залежності образу та збої середовища виконання не є першою проблемою. Подія називає відсутній розширений ресурс, що вказує на ємність GPU, справність плагіна пристрою, наявні виділення чи конфігурацію автомасштабувальника для GPU-вузлів. Веб-рівень може масштабуватися нормально, бо CPU-вузли не задовольняють запит GPU.

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

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

3. Прогону розподіленого навчання потрібно вісім GPU-воркерів, що запускаються разом. Чотири воркери в стані Running та утримують GPU, тоді як чотири в стані Pending, бо в кластері не лишилося ємності. Яка зміна платформи найкраще вирішує архітектурну проблему?

Додайте групове планування через пакетний планувальник на кшталт Volcano або використовуйте оператор навчання, що інтегрується з відповідною семантикою планування. Збій — це часткове розміщення розподіленого навантаження, а не готовність HTTP чи виявлення сервісу. Групове планування запобігає тому, щоб підмножина воркерів споживала GPU, коли повний набір не може запуститися, що покращує утилізацію та робить поведінку черги яснішою. Ключове те, що корисна одиниця планування — це група воркерів, а не кожен незалежний Pod.

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

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

5. Платформенна команда має одне щотижневе завдання перенавчання моделі шахрайства та один внутрішній ендпоінт інференсу шахрайства. Вони розглядають негайне встановлення великої наскрізної ML-платформи. Який найбільш обґрунтований перший крок?

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

6. Pod, що обслуговує модель, у стані Running, але користувачі отримують помилки протягом перших кількох хвилин після кожного розгортання. Логи показують, що контейнер завантажує ваги та прогріває модель у цей час. Що слід змінити?

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

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

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

8. Деплоймент інференсу запитує `nvidia.com/gpu: 1`, і кластер має GPU-вузол із виділюваною ємністю. Pod усе ще в стані Pending, а огляд вузла показує taint `accelerator=gpu:NoSchedule`. Яке найімовірніше виправлення?

Додайте відповідний toleration до Pod’а та, за бажанням, додайте вибір вузла чи affinity, щоб зробити бажаний пул GPU-вузлів явним. Taint відштовхує Pod’и, якщо вони не мають відповідного toleration, навіть якщо вузол має ресурс, який Pod запитує. Ліміт GPU резервує пристрій, тоді як toleration дозволяє планування на вузол із taint’ом. Селектори чи affinity потім роблять намір розміщення легшим для огляду та діагностики.

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

Розділ «Практична вправа: Імітуйте та діагностуйте запит планування GPU»

У цій вправі ви створите Pod, що запитує GPU, а потім огляньте результат планування. Вам не потрібен фізичний GPU для вправи. У типовому локальному кластері або кластері лише з CPU очікуваним результатом є Pod у стані Pending з подією планувальника, що показує, що жоден вузол не має достатньо ємності nvidia.com/gpu.

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

Terminal window
alias k=kubectl
  1. Створіть файл із назвою gpu-pod.yaml з Pod’ом, що запитує один GPU NVIDIA. Образ і команда справжні, але планувальник має знайти вузол, що повідомляє про nvidia.com/gpu, перш ніж контейнер зможе запуститися.
apiVersion: v1
kind: Pod
metadata:
name: gpu-test-pod
spec:
restartPolicy: Never
containers:
- name: cuda-container
image: nvidia/cuda:12.4.1-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1
Розв'язання для завдання 1

Важливим полем є ліміт розширеного ресурсу під resources.limits. У реальному GPU-кластері плагін пристрою NVIDIA або GPU Operator має повідомити про nvidia.com/gpu принаймні на одному вузлі, перш ніж цей Pod зможе запуститися. Налаштування restartPolicy: Never підходить для лабораторної роботи, бо Pod є одноразовим тестом планування, а не довготривалим сервісом.

  1. Застосуйте маніфест до вашого поточного контексту Kubernetes. Використовуйте одноразовий простір імен, якщо ваше середовище цього вимагає, але зберігайте назву Pod’а незмінною, щоб подальші команди збігалися.
Terminal window
k apply -f gpu-pod.yaml
Розв'язання для завдання 2

Очікувана команда — k apply -f gpu-pod.yaml після визначення alias k=kubectl, або еквівалентна повна kubectl apply -f gpu-pod.yaml. Якщо ваш контекст вказує на спільний кластер, використовуйте політику простору імен, якої вимагає ваше середовище, та зберігайте назву Pod’а стабільною. Операція apply лише просить API-сервер створити об’єкт; вона не доводить, що планування вдалося.

  1. Перевірте статус Pod’а та поспостерігайте, чи він запускається. У кластері лише з CPU він має залишитися в стані Pending, бо жоден вузол не повідомляє про розширений ресурс GPU.
Terminal window
k get pod gpu-test-pod
Розв'язання для завдання 3

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

  1. Опишіть Pod та прочитайте події планувальника біля низу виходу. Шукайте подію FailedScheduling, що згадує nvidia.com/gpu, бо ця подія пов’язує симптом із відсутнім планованим ресурсом.
Terminal window
k describe pod gpu-test-pod
Розв'язання для завдання 4

Найсильнішим доказом є подія від планувальника, що називає недостатню ємність nvidia.com/gpu. Ця подія означає, що планувальник не зміг знайти вузол із вільними виділюваними розширеними ресурсами, що також задовольняв би інші правила розміщення Pod’а. Не змінюйте спершу образ чи команду, бо Pod у стані Pending ще не дійшов до точки, де середовище виконання контейнерів могло б їх виконати.

  1. Огляньте виділювані ресурси вузлів, щоб пов’язати подію Pod’а зі станом кластера. Якщо жоден вузол не перелічує nvidia.com/gpu, у Kubernetes немає ємності GPU для виділення, навіть якщо якась фізична машина в середовищі має обладнання прискорювача, але без інтеграції плагіна пристрою.
Terminal window
k describe nodes
Розв'язання для завдання 5

Шукайте nvidia.com/gpu у секціях Allocatable. Якщо жоден вузол не повідомляє про цей ресурс, маніфест навантаження не може бути єдиним виправленням, бо в Kubernetes немає планованої ємності прискорювача. На реальній платформі наступні перевірки включали б існування пулу GPU-вузлів, встановлення драйверів, справність плагіна пристрою, taint’и вузлів та чи інший Pod уже спожив доступний GPU.

  1. Приберіть Pod після того, як ви зафіксували результат. Залишити Pod у стані Pending нешкідливо в лабораторії, але прибирання є частиною доброї гігієни кластера.
Terminal window
k delete pod gpu-test-pod
Розв'язання для завдання 6

Команда прибирання видаляє тестовий Pod та очищає об’єкт у стані Pending із простору імен. Прибирання має значення, бо повторювані лабораторії можуть залишати оманливі події планувальника чи назви, що конфліктують із пізнішими спробами. Якщо видалення зависає, перевірте, чи ваш поточний контекст та простір імен збігаються з об’єктом, який ви створили.

Використовуйте цей контрольний список критеріїв успіху, щоб перевірити, що ви відпрацювали весь шлях діагностики, а не лише створили YAML:

  • Ви створили gpu-pod.yaml із лімітом ресурсу контейнера, що запитує nvidia.com/gpu: 1.
  • Ви застосували маніфест за допомогою kubectl або псевдоніма k після визначення псевдоніма.
  • Ви поспостерігали за статусом Pod’а та правильно відрізнили збій планування Pending від збою середовища виконання контейнера.
  • Ви знайшли подію FailedScheduling чи еквівалентне повідомлення планувальника, що пояснює недостатні ресурси GPU в кластері лише з CPU.
  • Ви оглянули описи вузлів та пов’язали відсутню виділювану ємність nvidia.com/gpu із результатом планування.
  • Ви можете пояснити, що мало б змінитися в реальному GPU-кластері: GPU-вузли, драйвери, плагін пристрою чи GPU Operator, доступна ємність та будь-які потрібні toleration’и чи вибір вузла.
  • Ви видалили лабораторний Pod після завершення дослідження.

Для додаткової практики змініть маніфест, додавши фіктивний селектор вузлів, такий як accelerator: nvidia, та застосуйте його знову. Порівняйте подію планувальника з попереднім результатом. Точне формулювання може відрізнятися залежно від версії Kubernetes, але міркування має бути тим самим: планувальник може прив’язати Pod лише тоді, коли запити ресурсів, мітки вузлів, taint’и, toleration’и та доступна ємність — усі узгоджуються.

Модуль 3.9: WebAssembly та хмарно-нативні системи — Технологія, що з’являється і може доповнювати контейнери для швидко стартуючих, портативних та надійно ізольованих робочих навантажень.