Почему ваша первая попытка развернуть LLM в K8s провалится
Вы скачаете манифест из интернета, подставите свою модель, запустите kubectl apply и... получите Pod в статусе Pending. Потом в CrashLoopBackOff. Потом он запустится, но будет отвечать 20 секунд на простой запрос. Это стандартный сценарий.
Проблема в том, что LLM - не обычный микросервис. Это монстр, который жрет гигабайты видеопамяти, требует специфичной загрузки весов, ненавидит латентность и обожает падать при малейшем несовпадении версий CUDA.
На февраль 2026 года актуальные модели вроде GPT-OSS-130B или Claude-Next-Open требуют минимум 80GB GPU памяти в FP16. Без правильной архитектуры это превращается в ад.
Nova AI: что мы строим и зачем
Nova AI - это наша внутренняя платформа для запуска LLM в продакшене. Не для экспериментов, а для реальных нагрузок: чат-боты, генерация кода, анализ документов. Требования:
- Мультитенантность: разные команды, разные модели
- Автоскейлинг: от 0 до N реплик по запросу
- Мониторинг: метрики загрузки GPU, латентность, токены в секунду
- Быстрое развертывание: новая модель за 15 минут, не за 2 дня
- Экономия: GPU дорогие, нужно выжимать из них максимум
Стек проверен в бою: Kubernetes 1.30, KServe 0.12, NVIDIA GPU Operator 1.15, MLflow 2.15.
1Фундамент: готовим Kubernetes для GPU
Начнем с самого болезненного - настройки GPU. Если пропустить этот шаг, все остальное бессмысленно.
Установка GPU Operator (актуально на февраль 2026):
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia
helm repo update
# Для кластера с картами серии RTX 5000/6000 или A100/H100
helm install gpu-operator nvidia/gpu-operator \
--version 1.15.0 \
--namespace gpu-operator \
--create-namespace \
--set driver.enabled=true \
--set migManager.enabled=false \
--set toolkit.enabled=true \
--set operator.defaultRuntime=containerd \
--set dcgmExporter.enabled=trueКлючевые моменты:
operator.defaultRuntime=containerd- обязательно для современных K8sdcgmExporter.enabled=true- включаем метрики для Prometheus- MIG (Multi-Instance GPU) отключаем, если не используете A100/H100 с разделением
Проверяем:
kubectl get pods -n gpu-operator
kubectl describe node ваш-воркер | grep nvidia.com/gpuДолжны увидеть доступные GPU. Если нет - смотрите логи nvidia-device-plugin.
2KServe: не просто InferenceService, а с умом
KServe - это CRD для запуска ML моделей в K8s. Но его стандартная конфигурация для LLM - катастрофа.
Вот как НЕ надо делать:
# ПЛОХОЙ ПРИМЕР - так делать нельзя
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: bad-llm-service
spec:
predictor:
containers:
- name: kserve-container
image: tensorflow/serving:latest # УЖАС
resources:
limits:
nvidia.com/gpu: 1 # И ЭТО УЖАСПроблемы:
- Образ tensorflow/serving не подходит для LLM
- Лимит
nvidia.com/gpu: 1резервирует целую карту, даже если модель использует 10% памяти - Нет настроек загрузки модели, кэширования, батчинга
Правильная конфигурация для LLM в 2026 году:
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: nova-llm-gpt-oss-130b
annotations:
# Критически важные аннотации
serving.kserve.io/deploymentMode: ModelMesh # Для больших моделей
autoscaling.knative.dev/metric: concurrency
autoscaling.knative.dev/target: 10
autoscaling.knative.dev/window: 120s
spec:
predictor:
minReplicas: 0 # Масштабирование до нуля для экономии
maxReplicas: 4
containers:
- name: llm-inference
# Используем оптимизированные образы для LLM
image: ghcr.io/vllm/vllm-serving:0.5.0-cuda12.2
env:
- name: MODEL_ID
value: "microsoft/gpt-oss-130b"
- name: GPU_MEMORY_UTILIZATION
value: "0.95" # Используем 95% памяти GPU
- name: MAX_MODEL_LEN
value: "8192"
- name: DTYPE
value: "half" # FP16 для экономии памяти
- name: TENSOR_PARALLEL_SIZE
value: "2" # Для 130B модели на 2 GPU
resources:
limits:
# Ключевой момент: указываем память, а не целые GPU
nvidia.com/gpu.memory: 80000 # 80GB
cpu: "8"
memory: 64Gi
requests:
nvidia.com/gpu.memory: 80000
cpu: "4"
memory: 32Gi
ports:
- containerPort: 8080
protocol: TCP
# Health checks для LLM
livenessProbe:
httpGet:
path: /v2/health/live
port: 8080
initialDelaySeconds: 120 # Модель грузится долго!
periodSeconds: 30
readinessProbe:
httpGet:
path: /v2/models/model/ready
port: 8080
initialDelaySeconds: 180
periodSeconds: 20Важное изменение 2025-2026: KServe поддерживает nvidia.com/gpu.memory вместо nvidia.com/gpu. Это позволяет делиться GPU между несколькими моделями, если хватает памяти. Экономия до 60% на GPU.
3Оптимизация: заставляем GPU работать на 100%
GPU стоит $10,000+ в год. Если он простаивает - вы выбрасываете деньги.
Три уровня оптимизации:
| Уровень | Техника | Выигрыш |
|---|---|---|
| Модель | Quantization (GPTQ, AWQ), Flash Attention 3 | 2-4x скорость, в 2 раза меньше памяти |
| Сервер | vLLM с PagedAttention, Continuous batching | До 24x больше запросов в секунду |
| Инфраструктура | GPU sharing, Spot instances, Warm pools | До 70% экономии на инфраструктуре |
Наша конфигурация vLLM для максимальной производительности:
# Запускаем vLLM с оптимизациями 2026 года
vllm serve microsoft/gpt-oss-130b \
--quantization awq \
--gpu-memory-utilization 0.95 \
--max-model-len 8192 \
--tensor-parallel-size 2 \
--block-size 32 \
--swap-space 64 \ # Используем RAM если не хватает GPU памяти
--enable-prefix-caching \ # Кэшируем промпты
--max-num-batched-tokens 16384 \
--max-num-seqs 256Если у вас гибридный кластер с разными GPU, добавляем:
--device auto \ # vLLM сам распределит слои по GPU
--load-format auto \
--trust-remote-code4MLflow + KServe: полный цикл ML Ops
Модели меняются. Нужна система версионирования, тестирования и развертывания.
Архитектура:
- MLflow Tracking - логируем эксперименты, метрики, артефакты
- MLflow Models - упаковываем модель со всеми зависимостями
- MLflow Registry - управляем staging/production версиями
- KServe - развертываем модель из MLflow Registry
Регистрируем модель в MLflow:
import mlflow
import transformers
# Логируем эксперимент
with mlflow.start_run():
model = transformers.AutoModelForCausalLM.from_pretrained(
"microsoft/gpt-oss-130b",
torch_dtype=torch.float16,
device_map="auto"
)
# Сохраняем модель в формате MLflow
mlflow.transformers.log_model(
transformers_model={
"model": model,
"tokenizer": tokenizer
},
artifact_path="gpt-oss-130b",
registered_model_name="gpt-oss-130b",
# Критически важные метаданные для KServe
metadata={
"task": "text-generation",
"framework": "pytorch",
"gpu_required": "true",
"min_gpu_memory_gb": "80",
"quantization": "awq"
}
)Развертываем из MLflow в KServe:
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: mlflow-deployed-model
spec:
predictor:
model:
modelFormat:
name: mlflow
runtime: kserve-mlflow
storageUri: "models:/gpt-oss-130b/Production" # Берем продакшен версию
resources:
limits:
nvidia.com/gpu.memory: 80000
memory: 64GiМониторинг: что смотреть кроме CPU и памяти
Стандартные метрики Kubernetes бесполезны для LLM. Нужны специфичные метрики:
- GPU utilization: не только %, но и SM (Streaming Multiprocessor) активность
- GPU memory usage: давление на память, fragmentation
- Tokens per second: раздельно для input и output
- Time to first token: критично для UX
- Queue length: сколько запросов ждут обработки
- Batch size: эффективность continuous batching
Настройка Prometheus для сбора метрик NVIDIA:
# prometheus-nvidia-scrape.yaml
- job_name: 'nvidia-dcgm'
scrape_interval: 15s
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
target_label: __address__
regex: (.+);(.+)
replacement: $1:$2
- source_labels: [__meta_kubernetes_pod_container_port_number]
action: replace
target_label: __metrics_path__
regex: 9400
replacement: /metricsGrafana дашборд должен показывать:
- Тепловую карту загрузки GPU по нодам
- График латентности по перцентилям (p50, p95, p99)
- Эффективность использования GPU: стоимость токена в рублях
- Тренды: как меняется производительность после обновлений
Типичные ошибки и как их избежать
| Ошибка | Симптом | Решение |
|---|---|---|
| OOM при загрузке | Pod падает с CUDA out of memory | Используйте quantization, уменьшите max_model_len, добавьте --swap-space |
| Высокая латентность | TTFT > 5 секунд | Включите Flash Attention, кэширование, используйте более легкую модель |
| Низкая утилизация GPU | GPU utilization < 30% | Увеличьте max_num_seqs, настройте autoscaling по concurrency |
| Проблемы с сетью | Таймауты при больших контекстах | Увеличьте terminationGracePeriodSeconds, настройте Istio timeout |
| Гонка за GPU | Pending pods, недостаточно GPU | Используйте GPU sharing с memory limits, добавьте ноды по требованию |
Стоимость владения: цифры 2026 года
Давайте посчитаем на примере кластера из 4x RTX 6000 Ada (48GB каждая):
- Аренда сервера: $3,200/месяц
- Электричество (2kW * 24h * 30d * $0.15): $216/месяц
- Без оптимизации: 2 модели по 80GB каждая = 4 GPU
- С оптимизацией (quantization + sharing): 4 модели по 40GB = те же 4 GPU
Экономия: в 2 раза больше моделей на том же железе. Или те же модели, но на более дешевых картах.
Что будет дальше: прогноз на 2027
Тренды, которые уже видны:
- Специализированные AI чипы от Google (TPU v6), AWS (Trainium2), Cerebras - они придут в on-prem
- Умное распределение слоев модели между GPU, CPU и даже SSD - как в проекте Petals
- Стандартизация интерфейсов - OpenAI-совместимые эндпоинты станут де-факто стандартом
- Автоматическая оптимизация - система сама подберет quantization, batch size, parallel strategy под вашу модель и железо
Самая большая проблема, которая останется: люди все еще пытаются запускать 70B модели на 8GB картах. И будут пытаться.
Если строить мульти-нод кластер, смотрите в сторону InfiniBand и NVLink для снижения latency между GPU. Разница в производительности может достигать 10x.
И последний совет: никогда не используйте latest теги в образах. Особенно для CUDA. Особенно в пятницу. Особенно перед отпуском.