PunchMan City verdict has implications for football integrity, says FAInquirerPalawan confirms ASF case, strengthens containment measuresThe Jerusalem PostUS Senate unanimously passes bipartisan resolution honoring American October 7 victimsBollywood HungamaNushrratt Bharuccha to undergo spine surgery: Team issues official statement amid accident reportsESPN DeportesF1: Leclerc, el más rápido en la segunda práctica en SepangObservador DesportoOutdoors de apoio a CR7 e críticas a JJ surgem em LisboaSky TG24Festa dei Nonni, nonni cult di cinema, cartoni animati e serie da Lino Banfi a Coco e UpZDF heuteEntdecken Sie das ZDF-NachrichtenstudioХабрРусификация Omarchy Linux одним скриптомSportstarIndian hockey rocked by harassment complaints against umpire manager Gurinder Singh Sangha7sur7Mort du petit Wassim: Mohammed Taoussi condamné à la réclusion criminelle à perpétuitéBusiness AMWashington voert druk op: Europese Unie overweegt vrijgave van dieselvoorraden
The Daily Newsstand · Free, Always
Friday, October 2, 2026

[Перевод] Чьи это GPU: безопасные метрики с самообслуживанием для мультитенантного Kubernetes

Translate

«Мы вообще пользуемся этими штуками?» Этот вопрос прозвучал на разборе расходов на GPU — самой крупной статьи инфраструктурного счёта, и никто не смог на него ответить. Загрузку карт записывали каждую секунду, но метрики попадали в центральный Prometheus, куда тенанты не имеют доступа. Когда данные наконец проверили, обнаружили GPU, который одиннадцать дней подряд простаивал с нулевой загрузкой.

Команда VK Tech перевела статью с разбором о том, как дать каждой команде доступ только к своим метрикам, и шестью PromQL-запросов для поиска простаивающих карт.

Вопрос, который остановил совещание

На обычном разборе расходов на слайде показали траты на GPU за месяц — самую крупную статью инфраструктурного счёта. Кто-то спросил: «Мы вообще пользуемся этими штуками?» Никто не смог ответить. Самое дорогое оборудование оказалось и самым непрозрачным.

Ответ уже был в метриках. Загрузку каждого GPU записывали каждую секунду в течение нескольких месяцев и отправляли в центральный Prometheus инфраструктурной команды, где хранились данные всех команд из тысяч пространств имён. Но тенанты не могли получить к ним доступ: хранилище с метриками всех команд нельзя безопасно открыть ни одной из них. В результате видимость разделилась:

Когда мы наконец проверили данные, то нашли GPU, который одиннадцать дней подряд работал с нулевой загрузкой. Карта была выделена и включена, проходила health-check, но ничего не делала и оставалась невидимой для команды-владельца. Нельзя исправить то, чего не видишь. Если такие карты есть по всему парку, оборудование продолжает потреблять электричество при зелёных статусах health-check, а неопределённость превращается в ежемесячные расходы.

В этой статье мы рассказываем, как закрыли этот пробел: дали каждой команде безопасный доступ к собственным метрикам в режиме самообслуживания, не открывая чужие данные. Новый стек метрик и вендорская платформа не понадобились: решение собрано из CNCF-native компонентов, чтобы команды, отвечающие за бюджет на GPU, могли видеть использование выделенных им мощностей.

Почему решение «просто открыть доступ к Prometheus» не работает

Очевидным решением было бы дать каждой команде доступ на чтение к центральному Prometheus. Но мы столкнулись с двумя ограничениями, каждое из которых связано с оправданным архитектурным решением.

Первое это безопасность. Эндпойнт запросов Prometheus не учитывает пространства имён: если тенант может выполнить один запрос PromQL, он может выполнить любой, включая запрос к частоте обращений или планам по ёмкости другого тенанта. Модель, в которой все видят всё, нельзя безопасно применять в кластере с тысячами пространств имён.

Второе ограничение связано с масштабированием и хорошо знакомо платформенным инженерам как проблема шумного соседа. Центральный Prometheus уже собирает и хранит временные ряды для всего парка. Если к нему одновременно обратятся сотни инженеров с произвольными запросами, хранилище, от которого зависит вся инфраструктура, начнёт испытывать перегрузку. Тяжёлый диапазонный запрос одной команды повысит задержки для остальных.

По отдельности оба ограничения обоснованны. Вместе они оставляют нужные тенантам данные в хранилище, которое нельзя безопасно открыть для них. Каждому тенанту нужен собственный отобранный и изолированный набор метрик, доступный напрямую.

Метафора, которая всё объясняет

Представьте центральный Prometheus как огромный читальный зал, где личные блокноты всех команд лежат на открытых полках. Если раздать всем ключи от зала, вместе с доступом к своим данным команды получат доступ к чужим. А когда туда одновременно придёт много посетителей, читальный зал перестанет справляться с нагрузкой.

Нужен библиотекарь, который принимает читательский билет и приносит копию только нужной вам папки. Эту роль выполняет мультитенантный прокси.

Прокси перед Prometheus и контракт в YAML

Новый стек метрик не понадобился. Достаточно добавить перед существующим Prometheus тонкий слой, который учитывает принадлежность к тенанту. Решение строится на трёх принципах:

  • Идентификация. Система аутентифицирует клиента и определяет, к какому тенанту он относится.

  • Изоляция. Каждый запрос ограничивается пространством имён тенанта. Ограничение накладывается ниже уровня языка запросов, поэтому обойти его через PromQL нельзя.

  • Доставка. При необходимости система копирует отобранный набор метрик тенанта в его собственный небольшой Prometheus. Дашборды и алерты команды работают с хранилищем, которым она управляет.

Вторая часть решения — самообслуживание. Платформенная команда не сможет вручную поддерживать списки метрик для тысяч пространств имён, поэтому контракт оформлен как небольшой пользовательский ресурс Kubernetes — объект MetricAccess. В нём команда указывает, какие метрики ей нужны. Платформа поддерживает механизм, а тенант задаёт политику доступа. Решение построено на CNCF-native open source-компонентах.

Как всё устроено

Инфраструктурный Prometheus работает как раньше, а всё, что обращено к тенантам, находится за прокси:

На пути чтения запрос тенанта поступает в Nginx, который балансирует нагрузку между репликами прокси, затем проходит через kube-rbac-proxy для аутентификации и авторизации и попадает в прокси. Тот находит экземпляры Prometheus через Kubernetes API, отправляет запрос всем доступным бэкендам, оставляет только данные, разрешённые этому тенанту, и возвращает агрегированный результат.

На пути записи прокси периодически собирает отобранные метрики каждого тенанта и передаёт их через remote write в собственный Prometheus тенанта. Для тенантов с HA-конфигурацией прокси разрешает DNS-имена подов всех реплик и записывает данные в каждую из них, поэтому экземпляры хранят одинаковый набор метрик. В основе решения — привычные компоненты: Prometheus, обнаружение сервисов и remote write с моделью тенантности поверх.


Разворачивайте кластеры Kubernetes с Managed Containers

Автоматизируйте деплой
и снижайте затраты на инфраструктуру
до 60%

Попробовать

Изоляция без обходных путей

Самообслуживание безопасно только при обязательной изоляции. За неё отвечают два open source-компонента.

kube-rbac-proxy выполняет аутентификацию и авторизацию: определяет, кто отправил запрос и имеет ли он нужные права. Для этого он использует Kubernetes-native идентичность и RBAC — ту же модель, что применяется в API Server. Затем прокси передаёт подтверждённую принадлежность тенанта к пространству имён дальше по цепочке.

Изоляцию при выполнении запросов обеспечивает prom-label-proxy. Он переписывает каждый входящий запрос, добавляя селектор пространства имён. Например, запрос query перед отправкой в Prometheus превращается в query{namespace="your-namespace"}. Ограничение применяется ниже уровня PromQL, поэтому обойти его запросом нельзя.

Сам прокси работает в усиленной конфигурации: запускается не от root с UID 65534, использует корневую файловую систему только для чтения, сбрасывает все capabilities, запрещает повышение привилегий и работает от сервисного аккаунта с минимально необходимыми правами. Это многоуровневая защита критичного маршрута запросов.

Изоляция, которая снижает расходы

Фильтрация на этапе запроса не позволяет тенантам видеть данные друг друга, но собственный Prometheus тенанта всё равно может хранить гораздо больше метрик, чем ему нужно. Параметр metricIsolation переносит границу изоляции на этап сбора: метрики поступают через prom-label-proxy с уже применённым фильтром по пространству имён, поэтому тенант получает только собственные временные ряды.

Разница существенна:

Конфигурация

Хранимые ряды

Скорость запросов

Изоляция

metricIsolation: false

~10 000+ из всех пространств имён

Медленнее из-за большого набора данных

Только на этапе запроса

metricIsolation: true

~300 из этого пространства имён

Быстрее за счёт небольшого набора данных

На этапах сбора и запроса

Для типичного тенанта число хранимых рядов сокращается примерно на 97%: с более чем 10 000 до нескольких сотен. Небольшое хранилище быстрее отвечает на запросы, дешевле в эксплуатации и не может раскрыть данные, которых никогда не получало. Снижается и влияние шумных соседей: общее хранилище метрик всего парка больше не участвует в обработке повседневных запросов к дашбордам. Команда, с которой началась эта история, перешла от пустых дашбордов к собственному Prometheus.

Что на самом деле делает тенант

Чтобы подключиться, тенанту достаточно одного YAML-файла: в нём перечислены метрики и место, куда их доставлять:

apiVersion: observability.ethos.io/v1alpha1
kind: MetricAccess
metadata:
  name: gpu-team-metrics
  namespace: gpu-team
spec:
  source: gpu-team
  metricIsolation: true          # собирать только ряды этого пространства имён
  metrics:
    - "DCGM_FI_DEV_GPU_UTIL"                       # точное совпадение
    - "container_(cpu|memory)_.*"                  # регулярное выражение
    - '{__name__=~"nginx_ingress_controller_.*"}'  # селектор PromQL
  remoteWrite:
    enabled: true
    interval: "30s"
    target:
      type: "prometheus"
    prometheus:
      serviceName: "prometheus-operated"
      servicePort: 9090
      replicas: 2                # записывать в обе HA-реплики
      statefulSetName: "prometheus-gpu-team"
    extraLabels:
      tenant: "gpu-team"
      managed_by: "multi-tenant-proxy"

В списке метрик можно сочетать точные имена, регулярные выражения и селекторы PromQL. После применения манифеста прокси начнёт собирать и доставлять метрики. Запросы выполняются через обычный API Prometheus с заголовком тенанта:

curl -H "X-Tenant-Namespace: gpu-team" \

  "http://prometheus-multi-tenant-proxy:8080/api/v1/query?query=DCGM_FI_DEV_GPU_UTIL"

Требование одно: Prometheus тенанта должен принимать remote write (запустите его с --web.enable-remote-write-receiver). Остальное работает по умолчанию.

Шесть PromQL-запросов, которые покажут простаивающие GPU

Когда команда получает доступ к метрикам GPU, большую часть работы выполняют несколько запросов. Они рассчитаны на экспортёр в стиле DCGM; при необходимости замените имена метрик на те, которые использует ваша система. В запросах 5 и 6 также используется метрика скорости запросов к ingress, поэтому вместо nginx_ingress_controller_requests укажите метрику, которую экспортирует ваш ingress.

1. Средняя загрузка GPU по пространствам имён — основной показатель, которого команде не хватало:

avg by (namespace) (DCGM_FI_DEV_GPU_UTIL)

2. Количество фактически простаивающих GPU: загрузка ниже 5% за последний час. Этот запрос помогает найти неиспользуемые мощности:

count by (namespace) (avg_over_time(DCGM_FI_DEV_GPU_UTIL[1h]) < 5)

3. Используемая и общая память GPU по пространствам имён. Запрос помогает отличить загруженные GPU, упирающиеся в память, от выделенных, но пустующих:

sum by (namespace) (DCGM_FI_DEV_FB_USED)

  / sum by (namespace) (DCGM_FI_DEV_FB_USED + DCGM_FI_DEV_FB_FREE)

4. Потребляемая мощность по пространствам имён — приблизительный показатель текущих затрат:

sum by (namespace) (DCGM_FI_DEV_POWER_USAGE)

5. Загруженные GPU без трафика. Если GPU заняты, а ingress не получает запросов, это может указывать на зависшее задание:

avg by (namespace) (DCGM_FI_DEV_GPU_UTIL) > 70

  and sum by (namespace) (rate(nginx_ingress_controller_requests[5m])) < 1

6. Трафик есть, а GPU простаивают. Запросы поступают, но GPU не загружены — это может указывать на проблему с планированием, а не на нехватку мощностей:

sum by (namespace) (rate(nginx_ingress_controller_requests[5m])) > 10

  and avg by (namespace) (DCGM_FI_DEV_GPU_UTIL) < 5

Второй запрос вернул команду к исходной проблеме: он выявил GPU, которые простаивали часами. Это те самые скрытые расходы, с которых началась история: мощности, которые команда наконец увидела и смогла освободить.

Устойчивость в масштабе парка

Самообслуживание без ограничений лишь переносит проблему шумного соседа дальше по цепочке. Нагрузку ограничивают два механизма. Во-первых, прокси обрабатывает только отобранные наборы метрик, а не всю кардинальность парка. Во-вторых, интервалы сбора задаются для каждого тенанта отдельно и фактически работают как квота: одна команда может получать данные с шагом в 5 секунд, а пакетная нагрузка — раз в пять минут. Команды не платят за частоту сбора, нужную другим.

В нескольких кластерах система использует те же базовые механизмы: динамически обнаруживает бэкенды, выполняет remote write отдельно для каждого тенанта и записывает данные во все HA-реплики, чтобы переключение при отказе проходило незаметно. Систему всё равно нужно эксплуатировать, но её компоненты хорошо знакомы платформенной команде.

Что мы сказали бы себе прежним

  • Самообслуживанию всё равно нужны ограничения. Когда команда запрашивает «все метрики», чаще всего она ещё не понимает, какие именно ей понадобятся. Набор метрик лучше согласовывать вместе с командой, а вместо обширного списка разрешений подготовить разумные значения по умолчанию.

  • Кардинальность влияет на стоимость. metricIsolation определяет, будет ли хранилище содержать около 300 или 10 000 временных рядов. Включайте этот параметр, если только команде не нужен доступ к метрикам из нескольких пространств имён.

  • Сложности обычно возникают при доставке данных. Повторные попытки, экспоненциальная задержка между ними и запись во все HA-реплики — обязательные части системы. Заранее учитывайте сценарии отказа при расчёте ресурсов.

  • Изоляция не всегда нужна в полном объёме. Небольшим командам может быть достаточно доступа к отфильтрованным запросам; remote write стоит оставить для команд, которые поддерживают собственные дашборды и алерты.

  • Названия метрик могут различаться между кластерами. Половина ранних обращений с сообщением «нет данных» была связана с тем, что запросы использовали метрики, которые экспортёр не отдавал. Фиксируйте версии экспортёров и документируйте точные имена временных рядов.

Паттерн, который можно переиспользовать

Если отбросить детали реализации, этот подход подойдёт для любого мультитенантного кластера: прокси для аутентификации и авторизации, изоляция по меткам, которая применяется ниже уровня языка запросов, и необязательный remote write для каждого тенанта. Решение построено на CNCF-native open source-компонентах. Если вы уже используете Prometheus, основа у вас есть: не потребуется ни проприетарная платформа, ни отдельный самописный стек метрик.

Есть и другие подходы, которые стоит рассмотреть. Этот вариант позволил дать тысячам пространств имён собственное представление о метриках, не открывая всем доступ к общему хранилищу.

Команда, которая не видела метрики своих GPU, теперь поддерживает собственные дашборды и находит простаивающие мощности в течение часа. Общий Prometheus больше не становится узким местом, а команды работают со своими данными.

Попробуйте сами

Прокси выпущен как open source-проект под лицензией Apache 2.0; CRD MetricAccess, манифесты и примеры лежат в репозитории. В докладе на KubeCon + CloudNativeCon India 2025 показана живая демонстрация.

Репозиторий: https://github.com/adobe/prometheus-multi-tenant-proxy

Запись доклада: https://www.youtube.com/watch?v=gI40zpbES5w

Если эта публикация вас вдохновила и вы хотите поддержать автора — не стесняйтесь нажать на кнопку

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.