Как подружить Kubernetes с видеокартами NVIDIA
Представьте ситуацию: вы решили развернуть нейросеть или запустить тяжелый рендеринг в кластере Kubernetes. У вас есть мощные узлы с GPU, вы упаковали код в контейнер, запускаете под и... ничего не происходит. Контейнер просто не видит видеокарту. Kubernetes «из коробки» отлично умеет считать ядра процессора и гигабайты оперативки, но графические ускорители для него — это какая-то неведомая магия.
Чтобы эта магия заработала, NVIDIA выпустила k8s-device-plugin. Это тот самый «клей», который объясняет планировщику Kubernetes, сколько ресурсов GPU у вас есть, и пробрасывает нужные драйверы внутрь контейнеров.
Зачем это нужно в вашем кластере
Если коротко: без этого плагина ваши GPU в кластере — просто дорогое железо, которое потребляет электричество. Проект решает три конкретные задачи:
- Автоматически находит все видеокарты на узлах и сообщает об этом API-серверу Kubernetes.
- Следит за «здоровьем» карточек (если GPU «отвалится», плагин об этом узнает).
- Позволяет запускать контейнеры, которым нужен CUDA, без ручного пробрасывания путей к библиотекам драйверов.
Интересно, что NVIDIA пошла дальше простого проброса «одна карта — один контейнер». В современных версиях плагина завезли механизмы, которые позволяют использовать одну мощную карту сразу нескольким приложениям.
Главные фишки, которые упрощают жизнь
Делим одну GPU на всех
Раньше, если вашему микросервису нужно было чуть-чуть видеопамяти для простой модели, вам все равно приходилось отдавать ему целую карту. Это дико неэффективно. Сейчас в плагине есть два способа «распила»:
- Time-Slicing: это когда несколько процессов по очереди используют ресурсы GPU. Они делят время, но не изолированы друг от друга по памяти. Если один процесс упадет с ошибкой сегментации, может «прилететь» и остальным.
- CUDA MPS (Multi-Process Service): более продвинутый вариант. Он позволяет жестко ограничить объем памяти и вычислительную мощность для каждого контейнера. Это уже похоже на честную виртуализацию ресурсов.
Умная работа с MIG
Если у вас стоят флагманские карты вроде A100 или H100, вы наверняка слышали про Multi-Instance GPU (MIG). Плагин умеет работать с ними в «смешанном» режиме. Вы можете нарезать одну физическую карту на несколько независимых инстансов, и Kubernetes будет видеть их как отдельные ресурсы.
Автоматическая разметка узлов
В комплекте с плагином часто идет утилита GPU Feature Discovery (GFD). Она вешает на ваши ноды лейблы: какая модель карты стоит, сколько памяти, какая версия драйвера. Это позволяет гибко настраивать nodeSelector в манифестах. Хотите запустить обучение только на Tesla T4? Просто укажите это в селекторе.
Как это работает на практике
Сначала нужно подготовить сами узлы (поставить драйверы и NVIDIA Container Toolkit). Когда база готова, плагин ставится одной командой через Helm.
После установки в описании узла (kubectl describe node) появится новая строка в разделе Capacity: nvidia.com/gpu. Теперь в манифесте пода можно просто попросить ресурс:
spec:
containers:
- name: cuda-app
image: nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0
resources:
limits:
nvidia.com/gpu: 1
Кстати, есть забавный нюанс: если вы развернули плагин, но забыли указать лимит nvidia.com/gpu в манифесте пода, контейнер по умолчанию увидит вообще все видеокарты на этой ноде. В продакшене это может привести к неприятным сюрпризам, когда один забывчивый разработчик случайно займет память на всех картах сразу.
Технические нюансы и настройка
Плагин работает как DaemonSet. Это значит, что на каждой ноде с GPU будет крутиться маленький под, который общается с Kubelet через gRPC.
Для настройки параметров (например, включения того же Time-Slicing) NVIDIA предлагает использовать ConfigMap. Это удобно: вы описываете конфиг один раз, а потом через лейблы на нодах указываете, какой узел должен работать в режиме разделения ресурсов, а какой — отдавать GPU целиком под тяжелые задачи.
Пример конфига для разделения карты на 10 виртуальных частей:
version: v1
sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 10
Стоит ли внедрять
Если у вас в Kubernetes больше одной ноды с GPU или вы планируете давать доступ к видеокартам разным командам, то k8s-device-plugin — это стандарт де-факто.
Кому проект будет полезен:
- ML-инженерам: чтобы не думать о том, на какой именно сервер «приземлится» их Jupyter Notebook.
- DevOps-инженерам: для наведения порядка в ресурсах и мониторинга состояния железа.
- Data Scientist-ам: которым нужно быстро масштабировать инференс моделей.
Из минусов я бы отметил, что документация иногда кажется перегруженной из-за обилия вариантов установки (Docker, Containerd, CRI-O). Но если вы используете стандартный Helm-чарт, большинство проблем решается само собой. Проект живой, активно обновляется под новые архитектуры NVIDIA (вроде Blackwell), так что за актуальность можно не переживать.
