Три пода, разделяющие одну видеокарту, могут нарисовать в мониторинге суммарные 300% её загрузки. GPU в Kubernetes пока не наследуют привычную экономику CPU и памяти: платформенной команде приходится отдельно строить метрики, правила распределения затрат и защиту от неверного доступа к устройствам. Об этой проблеме сообщает The New Stack — и для российских команд, запускающих inference и ML-нагрузки в кластерах, это означает простой риск: красивый дашборд не гарантирует ни точного биллинга, ни рациональной утилизации дорогого железа.
Для CPU Kubernetes и ядро ОС уже дают удобную базу: можно сравнить запрос контейнера с фактическим потреблением, разложить данные по namespace и понять, кто держит лишние ресурсы. С GPU такой путь ломается сразу после перехода от схемы «одна карта — один под» к совместному использованию. NVIDIA DCGM Exporter по умолчанию публикует показатели физического устройства. При time-slicing или MPS несколько подов видят одинаковое значение по одной карте, хотя фактически делят её между собой. Графики при этом выглядят вполне пристойно — что делает ошибку особенно неприятной.
Проблема не сводится к наблюдаемости. GPU в планировщике Kubernetes обычно запрашивается целым числом, например nvidia.com/gpu: 1: запрос и лимит должны совпадать, а привычного переподписывания ресурса нет. Дробление, необходимое для inference, происходит ниже уровня планировщика — через time-slicing, MPS или MIG. Поэтому вопрос «какой под просит больше, чем использует» сначала превращается в другой: какую долю мощности он вообще получил и как эта доля определена.
Один процент загрузки — не один процент стоимости
Даже корректно снятая метрика GPU utilization не отвечает на главный финансовый вопрос. Она показывает, что ядра выполнялись в некоторой части интервала измерения, но не говорит напрямую о занятых вычислительных блоках, пропускной способности памяти или реальной полезной работе. Видеокарта может долго отображать 100% загрузки при низкой вычислительной отдаче. Обратная ситуация тоже возможна: упереться можно прежде всего в память, особенно когда фреймворки вроде vLLM резервируют значительную её часть на старте процесса.
Для эксплуатации это означает, что единого «процента полезности» у GPU нет. Команде придётся выбрать сигнал под свой тип нагрузки: объём занятой памяти, вычислительную активность, bandwidth или энергопотребление. Иначе попытка автоматически уменьшать заявки или распределять бюджет по одному общему индикатору приведёт к ложной экономии. В CPU-мире такой подход часто работает почти из коробки; GPU в Kubernetes требуют договориться о модели измерения до того, как на её основе появятся chargeback и KPI.
Наиболее надёжная отправная точка для атрибуции — память. Библиотека NVIDIA NVML позволяет увидеть её потребление на уровне процесса, а процесс можно связать с подом, namespace и командой. Полной арифметики всё равно не будет: часть памяти резервирует драйвер, и она не принадлежит ни одному workload. Зато для memory footprint данные пригодны для showback. С вычислениями сложнее: при параллельном исполнении процессов инструменты не дают честного ответа, какая команда получила 70% вычислительной доли, а какая — 30%.
Это различие важно и для финансового директора, и для владельца платформы. Облачный провайдер выставляет счёт за GPU-узел одной строкой, где смешаны CPU, память и ускоритель. Чтобы получить стоимость сервиса или команды, нужно отделить цену GPU, учесть модель карты и затем выбрать правило деления между workload. В публикации приведён показательный ориентир для AWS: минимальная совместимая с MIG конфигурация на A100 обходится примерно в 22 доллара в час, около 14 долларов на spot; сопоставимый CPU-only инстанс — примерно в 5 долларов в час. Даже без точной калькуляции по каждому региону разрыв объясняет, почему ошибка в распределении GPU заметнее, чем лишний CPU-лимит.
Планировщик знает не всё, что видит контейнер
Есть и более приземлённый риск. CUDA-образы нередко содержат переменную окружения NVIDIA_VISIBLE_DEVICES со значением all. В штатной конфигурации device plugin заменяет её набором устройств, выделенных поду. Но если подмена не сработала или runtime доверяет значению из контейнера, процесс способен увидеть и занять все GPU узла — независимо от того, что записал Kubernetes scheduler. Поэтому проверять надо не только объект Pod и его requests, но и процессы на самом устройстве.
Выбор режима совместного использования меняет всю математику. Time-slicing по очереди отдаёт устройство задачам без изоляции и допускает переподписывание. MPS позволяет ядрам разных процессов исполняться одновременно. MIG делит карту на аппаратные разделы, но даже при использовании одного раздела облако часто тарифицирует весь физический GPU; на A100 и H100 число таких инстансов ограничено семью. Dynamic Resource Allocation развивается в новых релизах Kubernetes, однако экосистема вокруг него, включая autoscaler Karpenter, ещё догоняет модель ресурсов.
Ближайшая практичная стратегия для платформенных команд выглядит менее эффектно, зато честно: использовать память для распределения расходов, вычислительную активность — как диагностический сигнал, а режимы sharing и фактическую видимость устройств фиксировать в инвентаре кластера. Главный вопрос теперь не в том, появится ли ещё один Grafana dashboard. Он в том, успеют ли инструменты наблюдаемости и биллинга догнать инфраструктуру до того, как GPU станут самой непрозрачной строкой в счёте за Kubernetes.