Production и облако · Production and cloud · урок 2 · 13 мин
Kubernetes для моделей: GPU-ноды, autoscaling, Helm
Kubernetes for models: GPU nodes, autoscaling, Helm
Зачем
После урока ты объяснишь, как своя модель живёт в Kubernetes: как GPU попадает в кластер, почему на GPU-узлах работают только модели, откуда берутся минуты холодного старта, почему autoscaling по CPU для модели бесполезен и зачем Helm и GitOps. Это второй слой вопроса «we want to serve our own fine-tuned model — how?», который отделяет того, кто запускал модели, от того, кто читал про Kubernetes.
Как GPU попадает в кластер
Сам по себе Kubernetes про GPU не знает. На узел ставят драйвер и device plugin (модуль, который объявляет устройство) от NVIDIA. После этого узел сообщает кластеру ресурс nvidia.com/gpu, и pod может его попросить. Правила из документации kubernetes.io (08.10.2026): GPU указывают в limits; если и в requests, значения должны совпадать. GPU выдаётся целыми устройствами, дробно его не попросить.
NVIDIA GPU Operator ставит весь набор разом: драйвер, container toolkit, device plugin, метки узлов по типу GPU и мониторинг DCGM (счётчики GPU). Метки нужны, чтобы различать карты: accelerator=l40s и accelerator=t4 — разные узлы для разных моделей.
Делить одну карту можно двумя способами. MIG (Multi-Instance GPU) режет карту на изолированные части со своей памятью, это умеют только дата-центровые карты вроде A100 и H100. Time-slicing (разделение по времени) объявляет одну карту, например, как четыре ресурса, но документация NVIDIA прямо пишет: «there is no memory or fault-isolation between replicas». Годится для dev, не для двух клиентов на одной карте.
Только модели на GPU-узлах: taint плюс affinity
GPU-узел дорогой, и на нём не должен поселиться сборщик журналов. Обратно: сервер модели не должен уехать на CPU-узел. Нужны два механизма вместе.
- Taint (метка-отталкиватель) на GPU-пуле:
nvidia.com/gpu=present:NoSchedule. Pods без разрешения туда не попадут. - Toleration (разрешение) плюс node affinity (притяжение к узлам с меткой) у сервера модели.
Документация формулирует ловушку так: «Tolerations allow scheduling but don't guarantee scheduling». Toleration только разрешает pod попасть на узел, но не тянет его туда. Без affinity сервер модели может оказаться на CPU-узле и не запуститься. Фраза для интервью: «taint repels everyone else, toleration plus affinity puts the model there».
Холодный старт: посчитай, из чего он состоит
Новая копия модели на новом узле проходит четыре этапа. Скорости ниже — допущения для примера, их надо мерить на своей платформе.
| Этап | Пример | Время |
|---|---|---|
| Узел появился (autoscaler создал машину) | — | минуты |
| Скачать image 12 ГБ при 200 МБ/с | 12 000 / 200 | 60 с |
| Скачать веса 70 ГБ из object storage при 500 МБ/с | 70 000 / 500 | 140 с |
| Загрузить в GPU и прогреть | — | десятки секунд |
Итого 4–6 минут до readiness. Что с этим делают: веса не в image и версионируются отдельно; cache весов рядом с узлом; заранее скачанные образы; тёплый минимум копий в рабочие часы; масштабирование по расписанию перед предсказуемым пиком (утро, день зарплаты). И startup probe с бюджетом больше худшего случая (урок a7-1).
Autoscaling: почему не CPU
HPA (Horizontal Pod Autoscaler) меняет число копий по метрике. Формула из документации: desiredReplicas = ceil(currentReplicas × currentMetricValue / desiredMetricValue). Цикл — раз в 15 с, отклонения в пределах 10 % игнорируются, уменьшение копий сглаживается окном 300 с, увеличение — без окна. Пример: 4 копии, в очереди в среднем 30 запросов на pod, цель 10 → ceil(4 × 30 / 10) = 12 копий.
Почему не CPU. Сервер модели упирается в GPU и в память под KV cache (кэш ключей и значений внимания для каждого разговора), а CPU почти не растёт с нагрузкой. Масштабировать по CPU — масштабировать по шуму. Посчитаем память. На один token нужно 2 × layers × kv_heads × head_dim × bytes. Для модели с 32 слоями, 8 KV heads, head_dim 128 в FP16: 2 × 32 × 8 × 128 × 2 = 131 072 байта ≈ 128 КиБ. Разговор на 8 000 tokens ≈ 1 ГиБ. На GPU с 80 ГБ, где 70 ГБ заняли веса, остаётся около 10 ГБ — примерно 10 таких разговоров одновременно. Поэтому сигнал для масштабирования — глубина очереди, число ожидающих запросов и занятость KV cache из метрик сервера, через custom metrics HPA или KEDA (надстройка для масштабирования по событиям).
KEDA умеет scale to zero (ноль копий без нагрузки). Для GPU-сервера в рабочие часы это плохая идея: первый клиент ждёт те самые 4–6 минут. Если pod не помещается на существующие узлы, Karpenter или Cluster Autoscaler создают новый узел. Это две петли подряд — копии, потом узлы, — отсюда минуты.
Сервер модели внутри pod
vLLM — стандартный выбор: PagedAttention (KV cache страницами, без дыр в памяти), continuous batching (на каждом шаге генерации в пакет добавляются новые запросы и убираются законченные), prefix caching, API, совместимый с OpenAI, квантизация. KServe — платформа поверх Kubernetes с ресурсом InferenceService, autoscaling вплоть до нуля и canary для моделей; vLLM работает внутри как backend. TGI от Hugging Face на 08.10.2026 в maintenance mode, авторы сами советуют vLLM, SGLang или llama.cpp.
Helm и GitOps: как это всё описать
Манифестов становится десятки, и для dev, staging и prod они отличаются парой чисел. Helm упаковывает их в chart (пакет шаблонов); values — параметры среды (-f values-prod.yaml, правый файл побеждает, --set сильнее файлов); release — установленный экземпляр с историей ревизий. helm upgrade даёт новую ревизию, helm rollback RELEASE REVISION возвращает прежнюю. Типовая схема: один chart агента и три файла values.
GitOps идёт дальше: желаемое состояние кластера лежит в Git, а контроллер Argo CD сравнивает его с живым. Расхождение помечается OutOfSync. Это даёт банку три вещи: аудит (каждое изменение production — commit с автором и review), откат (revert commit) и видимый дрейф (ручная правка kubectl edit сразу видна).
Схема
Термины · Key terms
- device plugin
- модуль, который объявляет GPU кластеру как ресурс
nvidia.com/gpu - GPU Operator
- набор NVIDIA: драйвер, device plugin, метки узлов, мониторинг
- MIG / time-slicing
- деление GPU с изоляцией памяти / переподписка без изоляции
- taint / toleration
- метка, отталкивающая pods от узла / разрешение для pod
- node affinity
- правило, которое притягивает pod к узлам с нужной меткой
- cold start
- время от решения добавить копию до её готовности
- HPA
- автомасштабирование числа pods по метрике
- KEDA
- масштабирование по событиям и очередям, включая scale to zero
- KV cache
- память под keys и values прошлых tokens каждого разговора
- continuous batching
- пакет запросов, который обновляется на каждом шаге генерации
- Helm chart / values / release
- пакет шаблонов / параметры среды / установленный экземпляр
- GitOps
- Git как источник правды о состоянии кластера
Сделай сам
10 строк Python без пакетов. Посчитай KV cache на token для Qwen3-8B: 36 слоёв, 8 KV heads, head_dim 128, BF16 (2 байта). Затем: веса 8,19 млрд параметров × 2 байта; сколько ГиБ останется под KV cache на карте 22 ГиБ, если 1,5 ГиБ уходит на служебную память, и сколько tokens контекста суммарно поместится. Выведи три числа.
Обсуди с тьютором: покажи расчёт и спроси, как изменится число одновременных разговоров на 8 000 tokens, если веса квантизовать в 4 бита, а KV cache — в FP8.
Проверь себя · ответ под вопросом
1Зачем на GPU-узлах нужны и taint, и node affinity? Разве не хватит одного?
2Почему HPA по 70 % CPU не годится для сервера модели?
3Из чего складываются минуты холодного старта и что из этого можно убрать?
Interview questions · US / UK
1We want to serve our own fine-tuned model on Kubernetes. How do you handle GPUs, cold start and autoscaling?
2Every morning at 9:00 p95 latency jumps from 3 s to 40 s for ten minutes. The model server has an HPA on 70% CPU. What do you check?
3Why would you use Helm and Argo CD together, and what does that give a regulated company?
Ключевые фразы · Say it aloud
- A toleration allows a pod onto a node; affinity pulls it theretoleration разрешает, affinity притягивает
- CPU is the wrong scaling signal for a GPU server; I scale on queue depthCPU — неверный сигнал, масштабирую по очереди
- Cold start is node, image, weights and warm-upхолодный старт: узел, образ, веса, прогрев
- Time-slicing shares a GPU without memory isolationtime-slicing делит карту без изоляции памяти
- KV cache, not compute, often caps concurrencyчисло одновременных разговоров часто ограничивает KV cache
- Git is the source of truth for what runs in productionчто работает в production, записано в Git
Материалы
- Kubernetes — Schedule GPUs — device plugins,
nvidia.com/gpu, GPU только в limits (6 мин) - Kubernetes — Taints and Tolerations — эффекты и разбор узлов со специальным железом (10 мин)
- Kubernetes — Horizontal Pod Autoscaling — формула, tolerance, окно scale-down, custom metrics (15 мин)
- vLLM docs — PagedAttention, continuous batching, OpenAI-совместимый сервер (5 мин на главную)
- Helm — Using Helm — chart, release, values, upgrade и rollback (12 мин)