Реализовать topology-aware scheduling для K8s device plugin с учётом NVSwitch доменов
ТЕХНИЧЕСКОЕ ЗАДАНИЕ: Реализовать topology-aware scheduling для K8s device plugin с учётом NVSwitch доменов
1. Цель задачи
Реализовать и протестировать plugin|device Kubernetes plugin|device plugin, который экспортирует топологию NVSwitch/NVLink в виде меток и аннотаций узла. Настроить скедулер так, чтобы pod’ы, использующие parallelism|tensor parallelism (TP), гарантированно размещались на GPU, соединённых через один NVSwitch, минимизируя меж-GPU задержки и перекрёстные обращения к памяти.
Ключевой результат После выполнения задачи вы сможете развернуть plugin|device plugin, который автоматически назначает GPU для tensor parallel workload’ов внутри одного NVSwitch домена, и ваш кластер обеспечит стабильно низкую латентность (<10 мкс на меж-GPU трансфер) при работе моделей вроде LLaMA-70B.
2. Исходные данные
| Что нужно | Откуда взять |
|---|---|
| Кластер Kubernetes с GPU-узлами (NVIDIA A100/H100, поддерживающие NVSwitch) | Реальный кластер (например, GPU-нода с 4–8 GPU) или эмуляция через симулятор топологии |
| Работающий kube-scheduler (vanilla или custom) | Стандартная установка Kubernetes |
| NVIDIA driver, nvidia-container-toolkit, nvidia-device-plugin | Устанавливаются через Helm |
Доступ к командам: nvidia-smi topo -m, nvidia-smi nvlink -s | Подтверждение топологии NVLink/NVSwitch |
| Тестовый workload с tensor parallelism (например, vLLM или TGI) | Docker-образ, HuggingFace модель (скачать или мини-тест) |
| Helm / kubectl, python3 | Установлены на машине администратора |
| (Опционально) Prometheus + Grafana для мониторинга GPU-взаимодействий | Установить заранее или добавить в этапы |
Если нет реального инструмента — симулируем:
- Разверните одноузловой кластер Kubernetes (kind/minikube) с поддержкой GPU через
nvidia-gpu-device-plugin. - Используйте симулятор топологии: напишите configmap с JSON, описывающим домены NVSwitch.
- plugin|Device plugin будет читать этот configmap эмулировать структуру NVSwitch.
- Для теста TP возьмите миниатюрную модель (например, GPT-2 1.5B через PyTorch + FSDP или MSCCL), настройте так, чтобы требовалось 2 GPU из одного домена и 2 из другого — это проверит корректность привязки.
3. Технологический стек
| Компонент | Инструменты | Назначение |
|---|---|---|
| Управление кластером | Kubernetes (1.27+), Helm 3, kubectl | Оркестрация pod’ов и device plugin |
| GPU-инфраструктура | NVIDIA driver >=535, nvidia-container-toolkit, nvidia-device-plugin (v0.14) | Работа с GPU внутри контейнеров |
| Анализ топологии | nvidia-smi topo -m, nvidia-smi nvlink -s, nvtop | Получение матрицы NVLink и доменов NVSwitch |
| Device plugin | Go 1.21+, Kubernetes device plugin API | Написание плагина, экспортирующего метки |
| Скедулинг | kube-scheduler (с приоритетами или через affinity/taints) | Размещение pod’ов согласно меткам |
| Тестовый workload | Python 3.10, PyTorch 2.0+, HuggingFace transformers, vLLM (опционально) | Запуск инференса с tensor parallelism |
| Мониторинг | Prometheus (gpu-exporter) + Grafana | Проверка меж-GPU трафика |
4. Этапы выполнения
Этап 1: Изучение топологии NVSwitch и определение требований (оценка времени: 2 часа)
Действия
-
Соберите топологию вашего GPU-узла
Зайдите на GPU-ноду и выполните:nvidia-smi topo -m nvidia-smi nvlink -s nvidia-smi nvlink -cЗапишите матрицу подключений: какие GPU находятся в одном NVSwitch домене, какие используют NVLink.
-
Создайте документацию топологии
Нарисуйте схему: NVSwitch (обычно 2–3 чипа) соединяют группы GPU (например, GPU 0-3 через NVSwitch 0, GPU 4-7 через NVSwitch 1).
Определите, сколько пар GPU могут общаться напрямую: для A100 NVSwitch поддерживает до 8 GPU в одном домене. -
Определите критерии для tensor parallelism
-
Сформулируйте API для device plugin
Ожидаемый результат этапа
Документированная топология и описание того, как будет выглядеть метки (пример: node gpu-node01 получит gpu-nvswitch-domain-0=0,1,2,3 и gpu-nvswitch-domain-1=4,5,6,7).
Этап 2: Разработка и деплой кастомного device plugin (оценка времени: 6 часов)
Действия
-
Скачайте шаблон nvidia-device-plugin
git clone https://github.com/NVIDIA/k8s-device-plugin cd k8s-device-plugin -
Напишите код, который читает топологию NVSwitch
Используйте go bindings для nvidia-smi (такие какgithub.com/NVIDIA/go-nvml/pkg/nvml).
Реализуйте функциюGetNVSwitchDomains():// Псевдокод: для каждой GPU получить её номер и сопоставить с доменом NVSwitch func GetNVSwitchDomains() map[string]string { // Использовать NVML nvmlDeviceGetNvLinkRemoteDeviceType или // получить через nvidia-smi topo парсинг вывода // ... } -
Расширьте экспорт ресурсов плагина
В методе ListAndWatch() модифицируйте объявление device’ов: для каждого GPU укажите дополнительные метки (labels) в аннотациях узла.
Для этого используйте k8s.io/client-go для обновления metadata node.Пример добавляемой аннотации на node:
metadata: annotations: nvidia.com/gpu-topo-nvswitch-domain-0: "0,1,2,3" nvidia.com/gpu-topo-nvswitch-domain-1: "4,5,6,7" -
Протестируйте плагин локально
Установите плагин как DaemonSet в кластере. Проверьте, что после запуска плагина на узле появились правильные аннотации:kubectl describe node <node-name> | grep -A5 nvidia -
Добавьте механизм приоритетной выдачи GPU
По умолчанию device plugin распределяет GPU в порядке лицензирования. Измените логику, чтобы pod с j тэгом tensor-parallel=true получал GPU из одного домена (разумеется, если запрашивает 2 или 4 GPU).В Allocate() проверьте, сколько GPU запрашивает pod, и если все они должны быть в одном домене — выбрать домен, где есть свободное количество ≥ запрошенного.
Ожидаемый результат этапа
Работающий device plugin, который:
- корректно отображает топологию (метки/аннотации),
- ограничивает выдачи GPU выходом за пределы домена, если pod явно того требует (через label selector).
Этап 3: Интеграция с kube-scheduler через node affinity (оценка времени: 3 часа)
Действия
-
Сконфигурируйте pod’ы с TP, чтобы они выбирали узел с нужной меткой
В spec pod’а добавьте:spec: nodeSelector: nvidia.com/gpu-topo-nvswitch-domain-0: "0,1,2,3" containers: - name: inference resources: limits: nvidia.com/gpu: 4 # 4 GPU из одного доменаНо стандартный nodeSelector привяжет ко всему узлу, а не к отдельным GPU. Чтобы выбирать GPU внутри узла, используйте предварительное выделение (pre-scheduling) через device plugin.
-
Настройте тождество (identity) домена через extended resource
Сделайте device plugin, который публикует домен как extended resource (например,nvidia.com/nvswitch-domain-0count = 4). Тогда pod может запросить конкретный ресурс и все GPU будут из этого домена:resources: limits: nvidia.com/gpu: 4 nvidia.com/nvswitch-domain-0: 4Это нестандартно; лучше использовать метки узлов и под специальный scheduler.
-
Разверните custom scheduler
Напишите простой scheduler (или используйте kube-scheduler с extender). Scheduler будет отказываться от назначения pod’а на узел, если не может выделить нужное количество GPU из одного домена.Реализация: scheduler extender в виде HTTP-сервиса, который проверяет:
- запрос
nvidia.com/gpu: X - топологию узла,
- доступность GPU в одном домене.
Простейшая реализация на Python (Flask) – 50 строк, не входит в этот этап, но можно использовать существующий
gpushare-scheduler-extender. - запрос
-
Настройте pod priority и pod group (для TP)
Через аннотациюscheduler.alpha.kubernetes.io/critical-podили используйтеcoscheduling.
Ожидаемый результат этапа
Pod с TP запросами (например, 4 GPU) размещаются на узлах, где есть свободная группа GPU в одном NVSwitch домене. Pod не может запуститься, если такой группы нет.
Этап 4: Тестирование и верификация (оценка времени: 4 часа)
Действия
-
Запустите тестовый workload с tensor parallelism
Используйте vLLM (небольшую модель, например,facebook/opt-1.3b). Конфигурация:apiVersion: v1 kind: Pod metadata: name: tp-test-1 labels: tensor-parallel: "true" spec: containers: - image: vllm/vllm-openai:latest args: ["--model", "facebook/opt-1.3b", "--tensor-parallel-size", "2"] resources: limits: nvidia.com/gpu: 2 -
Проверьте, что оба GPU из одного NVSwitch домена
После запуска pod’а выполнитеnvidia-smi nvlink -sна узле и найдите GPU, закреплённые за pod’ом (по PID). Убедитесь, что NVLink между ними активен. -
Измерьте latency меж-GPU обмена
Напишите простой скрипт или используйтеnvbandwidthвнутри контейнера. Сравните latency для GPU из одного домена vs разных доменов. -
Нагрузочное тестирование
Запустите несколько pod’ов (2-3) с разными запросами на количество GPU. Убедитесь, что scheduler не назначает pod, если нет свободной группы в домене. -
Соберите метрики
Если есть Prometheus/nvidia-exporter — понаблюдайте за метрикойDCGM_FI_DEV_NVLINK_BANDWIDTH_TOTAL. Для GPU из одного домена пропускная способность должна быть стабильно высокой.
Ожидаемый результат этапа
Подтверждено, что TP-модели работают с ожидаемой производительностью, а scheduler корректно изолирует группы GPU.
Этап 5: Документация и CI (оценка времени: 2 часа)
Действия
-
Напишите README
Опишите архитектуру, как разворачивать плагин, как тестировать. -
Создайте Makefile и Helm chart
Упакуйте device plugin как Helm chart, чтобы можно было развернуть одной командой. -
Напишите тесты
- unit тест для функции парсинга топологии,
- интеграционный тест (kubetest) на развертывание и проверку меток.
-
Задокументируйте ограничения
Например: текущая версия работает только для узлов с одинаковым количеством GPU в каждом домене.
Ожидаемый результат этапа
Репозиторий с code и документацией, готовый к повторному использованию.
5. Критерии приемки (Definition of Done)
- Device plugin разворачивается через Helm и корректно экспортирует метки NVSwitch домена на узлах.
- Тестовый pod с 2 GPU и меткой
tensor-parallel: "true"получает GPU, принадлежащие одному домену (подтверждается черезnvidia-smi nvlink -s). - При недостатке GPU в одном домене pod не может быть запланирован (остаётся в
Pending). - Для TP workload измерение latency меж-GPU (через
nvbandwidthили внутри модели) показывает значения < 5 мкс при передаче 1MB. - Код плагина покрыт unit-тестами (минимум 3 теста на парсинг топологии).
- Документация включает схему разворачивания и примеры конфигурации pod’ов.
- Все этапы воспроизводимы без прямого доступа к NVSwitch (через симулятор).
6. Ожидаемый результат
Основной артефакт
- Репозиторий GitHub (или директория) с исходным кодом кастомного device plugin на Go.
- Helm chart для его деплоя.
- README с инструкциями.
- Набор скриптов для тестирования (bash/Python).
Дополнительно (опционально):
- Scheduler extender с фильтрацией доменов.
- Демонстрация работы на видео (1-2 минуты) или GIF.
- JSON-схема топологии для симуляции.
7. Возможные сложности и их решение
| Сложность | Решение |
|---|---|
| Отсутствие доступа к NVIDIA NVML в контейнере device plugin | Программно читать /proc/driver/nvidia/gpus/*/nvlink или вызывать nvidia-smi через файловую систему (bind mount). |
| Невозможность протестировать на реальном кластере | Использовать симуляцию с помощью фейкового NVML (mock) – написать интерфейс NVML и подменять его. |
| Pod с TP требует чётное количество GPU, а домены не заполнены | Реализовать в scheduler осведомлённость о чётности и оставшихся GPU. |
| Device plugin не может изменить метки/аннотации узла из-за RBAC | Добавить ClusterRole с правами на nodes/status и nodes/annotations. |
| vLLM не поддерживает маленькие модели (ошибка out of memory) | Использовать модель OPT-125M или GPT-2 small; уменьшить контекст до 128 токенов. |
8. Бюджет времени (оценка)
| Этап | Время (часы) |
|---|---|
| Этап 1: Изучение топологии | 2 |
| Этап 2: Разработка device plugin | 6 |
| Этап 3: Интеграция scheduler | 3 |
| Этап 4: Тестирование | 4 |
| Этап 5: Документация и CI | 2 |
| Итого | 17 часов |
Примечание Для первого выполнения рекомендуется выделить 20-25 часов с учётом отладки.
9. Связанные вопросы из базы знаний
| Вопрос | Тема |
|---|---|
| 12 | Принципы работы NVLink и NVSwitch |
| 15 | Архитектура Kubernetes Device Plugin |
| 18 | Написание Custom Scheduler Extender |
| 22 | Tensor Parallelism в распределённом инференсе |
| 31 | Профилирование меж-GPU коммуникаций (nvbandwidth) |
| 45 | Helm chart структура и деплой |
| 67 | RBAC для изменений ресурсов узла |
| 88 | Prometheus exporter для GPU метрик |
| 112 | Как тестировать device plugin без реальных GPU (mock) |
| 145 | Оптимизация расстановки pod'ов с помощью topology-aware scheduling |
10. Чек-лист самопроверки
- Я умею собирать топологию NVSwitch через
nvidia-smi topo -mи интерпретировать матрицу. - Y устройство плагина корректно экспортирует аннотации узла с доменами (проверено
kubectl describe node). - Мой тестовый pod с 2 GPU не может быть запланирован, если свободны только 2 GPU из разных доменов.
- Я измерил latency меж-GPU и убедился, что внутри домена она <5 мкс.
- Код покрыт тестами, Helm chart устанавливается без ошибок, README содержит примеры.