Вы решили перейти от экспериментов с одним GPU-сервером к полноценному кластеру Kubernetes, который сможет запускать ML-обучение, инференс и другие GPU-задачи с возможностью масштабирования. Это не тривиальная задача, потому что GPU в Kubernetes — это не просто «добавил ресурс и работает». Здесь есть нюансы с драйверами, планировщиком, изоляцией, мониторингом и стоимостью. Давайте разберёмся, как сделать правильно.
- Что значит «масштабируемый GPU-кластер» на практике
- Выбор дистрибутива Kubernetes
- Архитектура GPU-нод
- Какие GPU выбрать
- Конфигурация ноды
- Настройка Kubernetes для работы с GPU
- NVIDIA GPU Operator — основа всего
- Что проверить после установки
- Планирование и распределение GPU
- Time-slicing — когда GPU нужно поделить
- MIG (Multi-Instance GPU) — аппаратная изоляция
- Node Selector и Taints/Tolerations
- Масштабирование кластера
- Cluster Autoscaler с GPU-нодами
- GPU-очереди и приоритеты
- Хранение данных для GPU-задач
- Мониторинг GPU-ресурсов
- Частые ошибки при построении GPU-кластера
- Что выбрать в зависимости от вашей ситуации
- У вас небольшая команда (2–5 человек), задачи — инференс
- Средняя команда (5–20 человек), смешанные задачи (обучение + инференс)
- Крупная организация, мультитенантность
- Практические рекомендации
- Итог
Что значит «масштабируемый GPU-кластер» на практике
Под масштабируемостью в контексте GPU-кластера я понимаю три вещи:
- Горизонтальное масштабирование — вы можете добавлять новые GPU-ноды без перестройки всей архитектуры.
- Эффективное распределение ресурсов — GPU не простаивают, а задачи получают нужное количество видеопамяти и вычислительных ядер.
- Предсказуемая работа — добавление или удаление нод не ломает существующие деплойменты, и планировщик справляется с очередями.
Если у вас 2–4 GPU на одной машине — можно обойтись ручным управлением. Но когда счёт идёт на десятки карт и десятки команд, которым нужны ресурсы, без правильной архитектуры Kubernetes быстро превращается в головную боль.
Выбор дистрибутива Kubernetes
Первое, с чем вы столкнётесь — какой Kubernetes использовать. Вариантов несколько, и выбор зависит от вашей ситуации:
| Вариант | Когда подходит | Сложность поддержки |
|---|---|---|
| Managed Kubernetes (GKE, EKS, AKS) | Команда небольшая, хочет быстрый старт. GPU-ноды поддерживаются из коробки у всех крупных провайдеров. | Низкая |
| Kubespray + самостоятельная установка | Нужен полный контроль, специфическая сеть или хранилище. | Средняя |
| Rancher / RKE / RKE2 | Баланс между контролем и удобством. RKE2 хорошо работает с GPU через автоматическую установку NVIDIA драйверов. | Средняя |
| OpenShift | Энтерпрайз-сценарий с жёсткими требованиями к безопасности и мультитенантности. | Высокая |
Мой совет: если вы не имеете веских причин для самостоятельной установки — берите managed-решение. У Google GKE поддержка GPU с автоматическим установлением драйверов NVIDIA работает стабильнее всего на сегодняшний день. EKS тоже неплох, но там больше ручной работы с нода-группами.
Архитектура GPU-нод
Какие GPU выбрать
Для production-кластера выбор обычно сводится к:
- NVIDIA A100 / H100 — для обучения больших моделей. Дорогие, но без альтернативы для LLM-тренинга.
- NVIDIA L4 / L40S — для инференса. Хороший баланс производительности и цены.
- NVIDIA T4 — бюджетный вариант для инференса и небольших задач.
- NVIDIA A10 / A16 — для виртуальных рабочих станций и лёгкого инференса.
Не смешивайте поколения GPU в одной ноде без крайней необходимости. Разные драйверы, разные версии CUDA — это путь к нестабильности.
Конфигурация ноды
Типичная конфигурация GPU-ноды для обучения:
- CPU: соотношение примерно 4–8 vCPU на один GPU (зависит от нагрузки на CPU при препроцессинге данных).
- RAM: 4–8 GB на один GPU. Для A100 80GB — минимум 256 GB RAM на ноду.
- Сеть: минимум 25 Gbps, лучше 100 Gbps для межнодного обмена при распределённом обучении.
- Диск: NVMe SSD, быстрый и просторный. Датасеты занимают десятки и сотни гигабайт.
Настройка Kubernetes для работы с GPU
NVIDIA GPU Operator — основа всего
Это самый важный компонент. GPU Operator автоматически разворачивает:
- NVIDIA драйверы на каждой GPU-ноде.
- NVIDIA Container Runtime — чтобы контейнеры видели GPU.
- Node Feature Discovery — Kubernetes узнаёт, какие ноды имеют GPU.
- GPU Feature Discovery — автоматическая аннотация GPU-характеристик.
- DCGM Exporter — метрики для мониторинга GPU.
Установка через Helm — стандартный путь:
helm install gpu-operator nvidia/gpu-operator \
--namespace gpu-operator \
--create-namespace \
--set driver.enabled=true \
--set toolkit.enabled=true
После установки ноды с GPU автоматически получают лейбел nvidia.com/gpu.present: true, и ресурс nvidia.com/gpu становится доступен для планировщика.
Что проверить после установки
Запустите тестовый под:
apiVersion: v1
kind: Pod
metadata:
name: gpu-test
spec:
restartPolicy: OnFailure
containers:
- name: cuda-test
image: nvidia/cuda:12.2.0-base-ubuntu22.04
command: ["nvidia-smi"]
resources:
limits:
nvidia.com/gpu: 1
Если nvidia-smi показывает вашу карту — базовая настройка работает. Если нет — проверяйте логи DaemonSet nvidia-driver-daemonset и nvidia-container-toolkit-daemonset.
Планирование и распределение GPU
Time-slicing — когда GPU нужно поделить
Не каждая задача требует целого GPU. Для инференса часто достаточно доли карты. GPU Operator поддерживает time-slicing — конфигурация, при которой несколько подов могут использовать один GPU по очереди.
Настраивается через ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: nvidia-device-plugin-config
namespace: gpu-operator
data:
config: |
version: v1
sharing:
timeSlicing:
renameByDefault: false
resources:
- name: nvidia.com/gpu
replicas: 4
Это создаст 4 «виртуальных» GPU на каждой физической карте. Подходит для инференса с низкой задержкой, но не для обучения — переключение между задачами добавляет накладные расходы.
MIG (Multi-Instance GPU) — аппаратная изоляция
На картах A100 и новее доступна технология MIG — физическое разделение GPU на несколько инстансов с изолированной памятью и вычислительными ядрами. Это надёжнее time-slicing, но жёстче в настройке.
MIG профили:
- 1g.5gb — один GPU делится на 7 инстансов по 5 GB видеопамяти.
- 2g.10gb — один GPU делится на 3 инстанса по 10 GB.
- 3g.20gb — один GPU делится на 2 инстанса по 20 GB.
- 7g.40gb — карта целиком для одной задачи.
Переключение MIG-профиля требует перезапуска ноды. Это не динамическая настройка — учитывайте при планировании.
Node Selector и Taints/Tolerations
Отделяйте GPU-ноды от CPU-нод с помощью taint:
kubectl taint nodes gpu-node-1 nvidia.com/gpu=true:NoSchedule
И добавляйте соответствующий toleration в поды, которым нужен GPU. Это предотвратит попадание CPU-задач на GPU-ноды и бесполезное потребление ресурсов.
Масштабирование кластера
Cluster Autoscaler с GPU-нодами
Cluster Autoscaler (CAS) умеет автоматически добавлять и удалять GPU-ноды. Но есть важные моменты:
- Провайдер облака должен поддерживать создание GPU-нод по API. У всех крупных провайдеров это работает.
- Настройте разумные лимиты — максимальное количество нод, чтобы не получить астрономический счёт при сбое очереди.
- GPU-ноды поднимаются дольше обычных (установка драйверов, загрузка образов). Увеличьте таймауты.
Пример настройки для GKE:
gcloud container clusters create gpu-cluster \
--zone us-central1-a \
--machine-type a2-highgpu-8g \
--accelerator type=nvidia-a100-80gb,count=8 \
--num-nodes 0 \
--enable-autoscaling \
--min-nodes 0 \
--max-nodes 10 \
--node-locations us-central1-a,us-central1-b
Обратите внимание: --min-nodes 0 — когда GPU не нужны, ноды удаляются, вы не платите за простаивающие карты.
GPU-очереди и приоритеты
Когда GPU меньше, чем желающих, нужна система приоритетов. Используйте PriorityClass:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: gpu-high-priority
value: 1000000
preemptionPolicy: PreemptLowerPriority
globalDefault: false
description: "Для критичных задач обучения"
Для более сложных сценариев — когда нужно гарантировать ресурсы для определённых команд — посмотрите в сторону Kueue (Kubernetes-native система очередей с поддержкой ресурсов типа GPU).
Хранение данных для GPU-задач
GPU-задачи — это почти всегда работа с большими объёмами данных. Типичные проблемы:
- Датасеты не помещаются на локальный диск ноды.
- Несколько подов хотят читать одни и те же данные.
- Скорость чтения ограничена сетевым хранилищем.
Варианты решений:
| Подход | Скорость | Когда использовать |
|---|---|---|
| HostPath / Local PV | Максимальная | Один под на ноду, датасет помещается на диск. |
| NFS (Filestore, EFS) | Средняя | Общий доступ для чтения, не критично к латентности. |
| Объектное хранилище (S3) | Зависит от сети | Первичное хранение, данные копируются на локальный диск перед работой. |
| Lustre / GPFS | Высокая | Распределённое обучение с параллельным доступом. |
Для распределённого обучения (PyTorch DDP, DeepSpeed) я обычно использую двухэтапный подход: данные лежат в S3, при старте задачи init-контейнер копирует нужную часть на локальный NVMe, а GPU-процесс читает уже локально.
Мониторинг GPU-ресурсов
Без мониторинга вы не узнаете, эффективно ли используются GPU. Стек, который я рекомендую:
- DCGM Exporter — метрики с каждой GPU: утилизация, температура, потребление памяти, пропускная способность PCIe.
- Prometheus — сбор и хранение метрик.
- Grafana — визуализация. NVIDIA предоставляет готовые дашборды для DCGM метрик.
Ключевые метрики, за которыми нужно следить:
- GPU utilization — если ниже 60% в среднем, вы переплачиваете за карты.
- GPU memory usage — помогает понять, правильно ли распределяются ресурсы.
- GPU temperature — перегрев означает проблемы с охлаждением или слишком плотную упаковку карт.
- PCIe bandwidth — узкое место при распределённом обучении.
Частые ошибки при построении GPU-кластера
Ошибка 1: Установка драйверов вручную. Если вы ставите NVIDIA драйверы на каждую ноду вручную — забудте про масштабируемость. Используйте GPU Operator или аналогичные инструменты. Ручная установка драйверов — причина 80% проблем с GPU в Kubernetes.
Ошибка 2: Отсутствие nodeSelector и taints. CPU-поды попадают на GPU-ноды, занимают ресурсы, GPU-задачи ждут. Всегда разделяйте ноды через taints + tolerations.
Ошибка 3: Игнорирование версии CUDA. Образ контейнера собран с CUDA 12, а драйвер на ноде поддерживает только CUDA 11. Проверяйте совместимость: версия драйвера должна быть >= версии CUDA в образе.
Ошибка 4: Нет лимита на GPU в namespace. Один разработчик запускает под с 8 GPU, и весь кластер встаёт. Обязательно настраивайте ResourceQuota и LimitRange для GPU-ресурсов.
Ошибка 5: Один GPU на несколько задач без изоляции. Time-slicing без контроля памяти — одна задача может занять всю память карты, и вторая упадёт с OOM. Используйте MIG или ограничивайте память на уровне пода.
Что выбрать в зависимости от вашей ситуации
У вас небольшая команда (2–5 человек), задачи — инференс
Берите managed Kubernetes (GKE или EKS), одну ноду с 2–4 L4 или T4, включите time-slicing. Не усложняйте — вам не нужны сложные очереди и мультитенантность. Настройте мониторинг и ResourceQuota — этого достаточно.
Средняя команда (5–20 человек), смешанные задачи (обучение + инференс)
Разделите ноды на пулы: один пул для обучения (A100, без time-slicing), другой для инференса (L4, с time-slicing). Настройте PriorityClass и базовые очереди. Используйте Kueue для управления ресурсами между командами.
Крупная организация, мультитенантность
Несколько отдельных кластеров или строгая изоляция через Virtual Cluster (vCluster). MIG для гарантированной изоляции GPU. Система учёта потребления ресурсов (Kubecost или аналоги). Отдельный пул нод для каждого типа нагрузки. Рассмотрите Run:ai или Anyscale для оркестрации GPU-ресурсов — это специализированные инструменты, которые решают задачи планирования лучше, чем голый Kubernetes.
Практические рекомендации
- Начните с одного типа GPU в ноде. Смешивание A100 и V100 на одной машине — путь к несовместимости драйверов и нестабильности.
- Используйте отдельный node pool для GPU. Это управляемее, чем одна нода с taint среди десятка без.
- Настройте Pod Disruption Budget для критичных GPU-задач. Чтобы обслуживание кластера не убило обучение на середине процесса.
- Храните чекпоинты в объектном хранилище. GPU-нода может исчезнуть в любой момент — прогресс обучения не должен теряться.
- Логируйте потребление GPU. Через месяц вы увидите, какие команды реально используют ресурсы, а какие запрашивают и забывают.
- Автоматизируйте обновление драйверов. GPU Operator делает это сам, но если вы без него — настройте автоматический ребилд нод при обновлении драйверов.
Итог
Построить масштабируемый GPU-кластер на Kubernetes — это не столько про установку технологий, сколько про правильную организацию процессов. Ключевые решения:
- Managed Kubernetes + GPU Operator — минимум ручной работы, максимум стабильности.
- Разделение нод по типу нагрузки — обучение отдельно, инференс отдельно.
- Time-slicing для инференса, MIG для гарантированной изоляции, целый GPU для обучения.
- Мониторинг утилизации — если вы не знаете, как используются GPU, вы не можете оптимизировать затраты.
- Квоты и приоритеты обязательны — иначе ресурсы съедят первые желающие.
Начните с малого: одна нода, GPU Operator, базовый мониторинг. Когда поймёте паттерны потребления — масштабируйте. GPU-ресурсы стоят дорого, и каждое неэффективное решение на старте обернется серьёзными расходами при росте кластера.
