English translation is not available yet. Showing Russian content.
Настроить auto-scaling для vLLM
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Настроить auto-scaling для vLLM
1. Цель задачи
Научиться настраивать горизонтальное масштабирование (horizontal pod autoscaling) инстансов vLLM на основе утилизации GPU. Сконфигурировать механизм, который автоматически добавляет или удаляет реплики vLLM, поддерживая целевой уровень загрузки GPU 70–80% без избыточного выделения ресурсов (overprovisioning).
Ключевой результат Рабочая конфигурация auto-scaling с HPA/KEDA, которая стабилизирует GPU utilization в диапазоне 70–80% под меняющейся нагрузкой, измеряемой синтетическим бенчмарком.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Kubernetes кластер (>=1.24) | Minikube / Kind / облачный K8s (EKS, GKE, AKS) |
| vLLM инстанс, развёрнутый в K8s | Docker образ vllm/vllm-openai:latest или собранный |
| Метрики GPU (utilization, memory) | NVIDIA DCGM Exporter, Prometheus |
| Prometheus + kube-state-metrics | Helm-чарты, установленные в кластере |
| HPA (Horizontal Pod Autoscaler) или KEDA | Встроенный в K8s или KEDA operator |
Если нет реального инструмента — симулируем:
- Развернуть локальный K8s кластер через Kind (1 control-plane, 2 worker nodes).
- Установить NVIDIA GPU Operator (если есть GPU) или использовать nvidia/dcgm-exporter без GPU для симуляции — в этом случае использовать custom metric на основе CPU utilisation, эмулируя GPU workload.
- Установить Prometheus stack через Helm (
prometheus-community/kube-prometheus-stack). - Написать простой Python-скрипт генератора нагрузки (отправка запросов к vLLM через OpenAI API).
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Контейнеризация | Docker, Kubernetes (Kind) | Запуск vLLM |
| GPU метрики | NVIDIA DCGM Exporter, Prometheus | Сбор utilization |
| Auto-scaling | HPA (Kubernetes) / KEDA | Горизонтальное масштабирование |
| Нагрузочное тестирование | Python + requests / locust | Генерация синтетического трафика |
| Мониторинг | Grafana | Дашборд GPU utilization |
| Конфигурация | Helm, YAML манифесты | Развёртывание компонентов |
4. Этапы выполнения
Этап 1: Развёртывание vLLM и сбор метрик GPU (1.5 часа)
Действия
- Создать namespace
vllm-systemв K8s. - Развернуть NVIDIA DCGM Exporter через Helm:
helm repo add nvidia https://helm.ngc.nvidia.com/nvidia helm upgrade --install dcgm-exporter nvidia/dcgm-exporter \ --namespace vllm-system \ --set serviceMonitor.enabled=true - Убедиться, что метрики поступают в Prometheus: DCGM_FI_DEV_GPU_UTIL.
- Развернуть vLLM с помощью Deployment и Service (пример deployment.yaml):
apiVersion: apps/v1 kind: Deployment metadata: name: vllm-server namespace: vllm-system spec: replicas: 1 selector: matchLabels: app: vllm-server template: metadata: labels: app: vllm-server spec: containers: - name: vllm image: vllm/vllm-openai:latest args: ["--model", "mistralai/Mistral-7B-Instruct-v0.2", "--port", "8000", "--tensor-parallel-size", "1"] ports: - containerPort: 8000 resources: limits: nvidia.com/gpu: 1 env: - name: HUGGINGFACE_HUB_CACHE value: "/data" - Установить ServiceMonitor для vLLM (если vLLM экспортирует prometheus метрики) или использовать kube-state-metrics для подов.
Ожидаемый результат этапа vLLM работает, метрики GPU utilization отображаются в Prometheus.
Этап 2: Создание HPA на основе GPU utilization (1 час)
Действия
- Настроить Prometheus Adapter для экспорта метрики DCGM_FI_DEV_GPU_UTIL как кастомной метрики в API metrics.
# values-prom-adapter.yaml rules: default: true custom: - seriesQuery: 'DCGM_FI_DEV_GPU_UTIL{namespace="vllm-system"}' resources: overrides: namespace: {resource: "namespace"} pod: {resource: "pod"} name: as: "gpu_utilization" metricsQuery: avg(<<.Series>>{<<.LabelMatchers>>}) by (pod) - Установить Prometheus Adapter:
helm install prometheus-adapter prometheus-community/prometheus-adapter -f values-prom-adapter.yaml. - Создать HPA ресурс:
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: vllm-hpa namespace: vllm-system spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: vllm-server minReplicas: 1 maxReplicas: 5 metrics: - type: Pods pods: metric: name: gpu_utilization target: type: AverageValue averageValue: 75 # 75% utilization target - Проверить, что HPA видит метрику:
kubectl get hpa -n vllm-system.
Ожидаемый результат этапа HPA создан, target metric показывает актуальное значение GPU utilization.
Этап 3: Нагрузочное тестирование и проверка масштабирования (1 час)
Действия
- Написать скрипт генерации нагрузки
load_gen.py:import requests import concurrent.futures import time url = "http://<vllm-service>:8000/v1/chat/completions" payload = { "model": "mistralai/Mistral-7B-Instruct-v0.2", "messages": [{"role": "user", "content": "Расскажи подробно про машинное обучение."}], "max_tokens": 512 } def send_request(): requests.post(url, json=payload, timeout=30) # Параллельные запросы while True: with concurrent.futures.ThreadPoolExecutor(max_workers=10) as executor: futures = [executor.submit(send_request) for _ in range(20)] concurrent.futures.wait(futures) time.sleep(2) - Запустить скрипт, постепенно увеличивая количество параллельных запросов (например, 5 → 10 → 20 → 50).
- Наблюдать в Grafana (или через
kubectl top pods) изменение GPU utilization. - Когда utilization превысит 80%, HPA должен начать масштабирование. Зафиксировать количество реплик до и после.
Ожидаемый результат этапа При нагрузке количество реплик увеличивается до стабилизации utilization ~75%; при спаде нагрузки реплики уменьшаются до minReplicas.
Этап 4: Тюнинг параметров и оптимизация (1 час)
Действия
- Настроить cool down и stabilization window в HPA:
behavior: scaleDown: stabilizationWindowSeconds: 60 policies: - type: Pods value: 1 periodSeconds: 60 scaleUp: stabilizationWindowSeconds: 30 - Протестировать сценарий резкого скачка нагрузки (flash crowd) — HPA не должен thrash.
- Оптимизировать target averageValue: если utilisation колеблется, попробовать 70% для более агрессивного масштабирования.
- Включить resource metrics (CPU, memory) как дополнительную метрику для HPA, чтобы избежать масштабирования под 0 при отсутствии GPU нагрузки.
- Установить KEDA ScaledObject как альтернативу, если требуется более тонкая настройка.
Ожидаемый результат этапа HPA стабильно поддерживает utilization 70-80% без лишних реплик и без частых масштабирований.
Этап 5: Документирование и дашборд (30 минут)
Действия
- Создать Grafana dashboard с панелями:
- Написать README с инструкцией по развёртыванию автоскейлинга.
- Зафиксировать конфигурационные файлы (deployment.yaml, hpa.yaml, values-prom-adapter.yaml) в Git.
Ожидаемый результат этапа Документированный набор конфигураций и дашборд для мониторинга масштабирования.
5. Критерии приемки (Definition of Done)
- HPA успешно создан и видит custom metric
gpu_utilizationдля всех подов. - При синтетической нагрузке 50 параллельных запросов количество реплик увеличивается с 1 до 3-5 в течение 3 минут.
- Утилизация GPU стабилизируется в диапазоне 70–80% (±5%) в течение периода нагрузки.
- После прекращения нагрузки количество реплик возвращается к minReplicas за время не более 3 минуты.
- Ни один инстанс не достигает 100% GPU utilization дольше 30 секунд.
- Дашборд Grafana отображает ключевые метрики автоскейлинга.
- Все конфигурационные файлы сохранены в репозитории.
- Выполнен сценарий thrash-теста: резкое повышение нагрузки не вызывает циклического масштабирования (scale-up/down чаще раза в минуту).
6. Ожидаемый результат
Основной артефакт Набор YAML-манифестов:
deployment.yaml— Deployment vLLM с resource limitshpa.yaml— HPA с кастомной метрикойvalues-prom-adapter.yaml— конфигурация Prometheus Adaptervalues-dcgm-exporter.yaml— настройки DCGM Exporterload_gen.py— скрипт для генерации нагрузкиREADME.md— описание и команды развёртывания
Дополнительные результаты
- Grafana dashboard JSON (экспортированный).
- Отчёт о тестировании: графики utilization, количество реплик, задержки.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| GPU метрика не появляется в Prometheus | Проверить serviceMonitor у DCGM Exporter, label selector у Prometheus, namespace |
| HPA не видит кастомную метрику | Убедиться, что Prometheus Adapter настроен правильно и метрика доступна по адресу /apis/custom.metrics.k8s.io/v1beta1 |
| Масштабирование слишком медленное | Уменьшить stabilizationWindowSeconds для scaleUp, увеличить агрегацию метрики |
| Частое масштабирование (thrashing) | Установить поведение scaleDown с задержкой и полиси, использовать несколько метрик (CPU + GPU) |
| vLLM не успевает загрузить модель на новой реплике | Использовать ReadinessProbe с проверкой /health, предварительно скачать модель в PVC или образе |
| Нет физического GPU | Использовать CPU-only vLLM или эмуляцию через DCGM Exporter на CPU (метрика = CPU utilization) |
8. Бюджет времени (оценка)
| Этап | Время |
|---|---|
| Этап 1: Развёртывание vLLM и сбор метрик GPU | 1.5 ч |
| Этап 2: Создание HPA на основе GPU utilization | 1 ч |
| Этап 3: Нагрузочное тестирование | 1 ч |
| Этап 4: Тюнинг и оптимизация | 1 ч |
| Этап 5: Документирование и дашборд | 0.5 ч |
| Итого | 5 ч |
Примечание Для первого выполнения рекомендуется заложить +2 ч на отладку Kubernetes/Prometheus. Если нет GPU, время увеличится на 1 ч за счёт симуляции.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 55 | Как настроить Prometheus Adapter для кастомных метрик? |
| 112 | Параметры HPA: stabilizationWindow и поведение при scale up |
| 203 | Мониторинг GPU utilization в Kubernetes через DCGM Exporter |
| 401 | vLLM: оптимальная конфигурация tensor-parallel-size для масштабирования |
| 567 | Экономика auto-scaling: расчёт стоимости при переключении реплик |
| 688 | KEDA ScaledObject vs HPA: когда что использовать |
| 789 | Оптимизация холодного старта vLLM в auto-scaling |
| 832 | GPU фрагментация памяти: влияние на масштабирование |
| 899 | Best practices: target utilization для GPU в inference |
| 900 | Тестирование auto-scaling с Locust и синтетическими данными |
10. Чек-лист самопроверки
- Я убедился, что метрика GPU utilization корректно агрегируется по поду (avg по всем GPU в поде).
- Я проверил, что HPA использует
averageValue, а неaverageUtilization, так как последний не поддерживается для custom metrics. - Я протестировал сценарий с низкой нагрузкой — реплика не уменьшается ниже 1.
- Я настроил
behaviorчтобы избежать oscillation. - Я сохранил все конфигурационные файлы и скрипты в репозиторий.
- Я выгрузил дашборд Grafana и приложил к результатам.
- Я выполнил тест на thrashing: резкий скачок нагрузки не вызывает частых scale-up/down.