Dynamic Resource Allocation, или DRA, в Kubernetes не отменяет проект HAMi для совместного использования графических процессоров, но меняет распределение ролей между ними. После того как DRA достиг общедоступности в Kubernetes v1.34 и был включен по умолчанию начиная с v1.35, Kubernetes получил возможность нативно понимать и планировать запросы на частичные квоты ресурсов устройства. Однако соблюдение этих квот внутри контейнера при вызовах CUDA не входит в задачи DRA — здесь роль HAMi-core остается ключевой.
Статья CNCF, написанная Mesut Oezdil, представляет аналитическое сравнение этих двух этапов и объясняет, как HAMi перестраивает часть своей экосистемы поверх DRA вместо отказа от проекта. Автор отмечает, что вопрос заключается не в том, заменит ли один проект другой, а в том, какие функции HAMi теперь покрываются встроенными возможностями Kubernetes.
Почему для совместного использования GPU потребовались специальные решения?
Интерфейс Device Plugin в Kubernetes изначально умел в основном подсчитывать устройства. Традиционный запрос, например nvidia.com/gpu: 1, означал резервирование целой карты, не предоставляя нативного языка для запроса 8 000 МБ памяти карты или 10% ее вычислительной мощности.
Для решения этой задачи HAMi использует расширенные ресурсы, такие как nvidia.com/gpumem и nvidia.com/gpucores. Однако планировщик Kubernetes по умолчанию воспринимает эти значения как абстрактные числа: он не знает, что память и вычислительная мощность должны предоставляться одной и той же физической картой, и сам не может определить, превысят ли несколько квот емкость конкретной карты.
Поэтому традиционный процесс использует webhook для изменения запроса, специальное расширение планировщика для фильтрации узлов и выбора идентификатора устройства, а затем сохраняет решение в annotation. Позже Device Plugin считывает это решение, чтобы внедрить такие ограничения, как CUDA_DEVICE_MEMORY_LIMIT_0=8000m и CUDA_DEVICE_SM_LIMIT=10, а также предварительно загрузить библиотеку libvgpu.so для принудительного соблюдения ограничений.
Согласно статье, DaoCloud запустила более 10 000 GPU в более чем 10 центрах обработки данных, используя этот подход. Однако его архитектура по-прежнему зависит от специального формата annotations и компонентов, которые понимает HAMi. Именно этот разрыв призван устранить DRA.
Что добавляет DRA?
DRA заменяет модель подсчета устройств моделью требований, используя четыре основных объекта в интерфейсе resource.k8s.io/v1:
- ResourceSlice: публикуется драйвером устройства и описывает фактическое оборудование каждого узла, включая модель, память и архитектуру.
- DeviceClass: определяет классы устройств и их фильтры с использованием выражений CEL.
- ResourceClaim: создается владельцем рабочей нагрузки для запроса устройства в соответствии с классом, селекторами и ограничениями.
- ResourceClaimTemplate: создает отдельное требование для каждого экземпляра рабочей нагрузки.
Планировщик назначает конкретное устройство требованию до привязки контейнера, а результат отображается в состоянии ResourceClaim как структурированный объект API. Это предоставляет решению нативное место, доступное для чтения через kubectl, защищаемое с помощью RBAC и пригодное для использования другими контроллерами, вместо хранения в виде текстовой строки в annotation.
Однако одного базового DRA недостаточно для совместного использования памяти в стиле HAMi. Важным расширением здесь является Consumable Capacity, появившееся в экспериментальном виде в v1.34 за флагом DRAConsumableCapacity, а затем ставшее экспериментальным и включенным по умолчанию начиная с v1.36. Это расширение позволяет драйверу объявлять, что устройство принимает несколько распределений, а требованию — запрашивать определенное количество именованного ресурса на устройстве, например памяти или вычислительной мощности.
Так сопоставление ресурсов HAMi становится почти прямым: gpumem превращается в запрос емкости памяти, gpucores — в запрос вычислительной емкости, а проверка того, располагает ли карта необходимой свободной емкостью, переносится с расширения планирования HAMi непосредственно в планировщик Kubernetes.
Планирование не означает соблюдение ограничений
Анализ подчеркивает, что DRA отслеживает обещания, данные планировщиком, но не препятствует контейнеру превысить их во время выполнения. Вызовы CUDA не знают, что указано в ResourceClaim, и жадная рабочая нагрузка может попытаться потребить дополнительную память за счет другого контейнера.
Эту функцию выполняет HAMi-core посредством библиотеки C — libvgpu.so, которая перехватывает вызовы CUDA и NVIDIA Management Library и применяет ограничения из пользовательского пространства. Согласно приведенному в статье примеру, если два контейнера получают по 8 000 МБ, контейнер, превысивший свою квоту, получает ошибку CUDA out of memory при достижении своего лимита, тогда как другой контейнер продолжает работу.
Такая программная защита не является заменой аппаратному разделению в средах с враждебными многопользовательскими арендаторами. Рабочая нагрузка, обходящая предварительную загрузку библиотеки, использующая статическую линковку с драйвером CUDA или применяющая такие настройки, как CUDA_DISABLE_CONTROL, может избежать перехвата. Автор отмечает, что NVIDIA Multi-Instance GPU, или MIG, лучше подходит для аппаратной изоляции, тогда как программный перехват обеспечивает точность до шагов в 1 МБ для памяти и 1% для вычислений по сравнению со статическими профилями MIG.
Как HAMi перестраивает свою экосистему поверх DRA?
Новая архитектура распределена между тремя репозиториями, выполняющими разные функции:
- k8s-dra-driver: публикует память и вычислительную мощность каждого GPU как потребляемую емкость в ResourceSlices, запускает плагин kubelet и подключает контейнеры через CDI с присоединением механизмов принудительного соблюдения ограничений HAMi-core.
- HAMi-DRA: webhook для изменения запросов при приеме, который удаляет традиционные расширенные ресурсы из запросов и создает эквивалентные ResourceClaims, сохраняя annotations для выбора UUID и типа устройства. Согласно статье, HAMi-DRA v0.2.0 была готова к эксплуатации в производственной среде вместе с HAMi v2.9, после чего серия выпусков продолжилась версией v0.2.1.
- HAMi: документирует режим DRA как вариант установки начиная с версии v2.8, а также по умолчанию включает компонент мониторинга и предоставляет метрики устройств для каждого контейнера через Prometheus на порту 31995.
Одно из преимуществ HAMi-DRA заключается в том, что планирование остается за планировщиком, управляющим кластером. Это позволяет использовать Volcano, KAI Scheduler или любой другой планировщик, понимающий DRA, без добавления специальной интеграции с HAMi. Однако у такого решения есть цена: HAMi-DRA не имеет собственного планировщика и поэтому не гарантирует решений с учетом топологии, например выбора пары GPU, соединенных через NVLink.
Требования и практический выбор
Режим DRA требует Kubernetes v1.34 или новее с включенным DRAConsumableCapacity. В версиях v1.34 и v1.35 этот флаг является экспериментальным и отключен по умолчанию, что может препятствовать его использованию в управляемых сервисах, не позволяющих изменять настройки API-сервера. В v1.36 он стал экспериментальным и включенным по умолчанию. Кроме того, необходим runtime с поддержкой CDI, например containerd или CRI-O с включенным CDI, драйвер NVIDIA версии 440 или новее, а также подходящий DRA-драйвер для конкретного типа ускорителя.
В статье говорится, что путь NVIDIA является наиболее зрелым; также доступна поддержка Ascend и Enflame, а Hygon DCU документирован через k8s-dcu-dra-driver. В то же время традиционный режим HAMi начиная с v2.9 охватывает более 12 семейств устройств, включая Cambricon MLUs, Iluvatar, MetaX, Moore Threads, Kunlunxin, AWS Neuron и Vastai. Поэтому кластеры с несколькими поставщиками, вероятно, продолжат использовать традиционный путь, пока охват DRA-драйверами не расширится.
Не следует одновременно запускать режим DRA и традиционный режим Device Plugin в одном кластере, поскольку две системы планирования будут выглядеть так, будто управляют одной и той же ёмкостью, не видя обещаний другой системы. Согласно оценке автора, традиционный режим подходит для управляемых кластеров, которые не предоставляют шлюзы функций, для более старых версий и для мультиизготовительских парков. Кластеры NVIDIA, в которых контролируется уровень Kubernetes, особенно на v1.36, могут испытать режим DRA в тестовой среде, начав с HAMi-DRA, чтобы избежать изменения существующих файлов развёртывания.
Consumable Capacity по-прежнему окончательно не стабилизирован в Kubernetes, а Helm-чарт k8s-dra-driver всё ещё помечен как находящийся в разработке; кроме того, охват поставщиков в DRA остаётся ниже, чем в традиционном режиме. Итог статьи заключается в том, что DRA отвечает за язык запросов и планирование, тогда как HAMi-core сохраняет возможность выполнения внутри контейнера; иными словами, их взаимоотношения движутся в сторону интеграции, а не замены.