Привет, Хабр! Я Даниил Салман, техлид по контейнеризации в К2 Тех. Эта статья написана по мотивам моего доклада для конференции DevOops. Разберёмся, как сделать такую ML-«песочницу», где Data Scientist пишет код, а всё остальное (установка драйверов, выделение ресурсов, деплой и тренировка модели, сбор метрик) уже настроено на бэкенде. Написали максимально просто и доступно, чтобы понять смог даже человек с минимальным погружением в тему. Идеи из этой статьи можно применять в любой инфраструктуре — важно лишь понимать основы: как работает k8s-кластер, Docker и python-фреймворки. Итак, поехали!
С какими болями сталкиваются ML-команды

Но прежде чем перейти к самому интересному, немного истории. Познакомьтесь с лирическим героем этого рассказа — DevOps-инженером Германом. Герман — опытный специалист, но однажды он столкнулся с типичной проблемой: как развернуть инфраструктуру для ML-моделей быстро и надёжно.
У Германа было несколько собственных k8s-кластеров — он их поддерживал, следил за метриками, решал инциденты. Обычная инженерная рутина. Но однажды после очередной IT-конференции его начальник пришёл с «гениальной идеей»:
— Герман, нам нужна своя ML-платформа, как сейчас модно. Разберись, как это работает и что для этого надо.
С этого момента у Германа без остановки кипела голова. YouTube, сотни статей на Хабре, тысячи вкладок, непонятные аббревиатуры вроде MIG и MPS — а ясности всё меньше. Герман сидит перед экраном, читает и всё больше погружается в хаос.

В какой-то момент он вспоминает, что его знакомый Данила работает в интеграторе и занимается инфраструктурой для ML. Герман звонит, рассказывает о своей боли — и получает несколько ссылок на git-репозитории, пару статей и вендорскую документацию. Через пять дней он пишет: — Данила, ты что, крейзи? Где же ты был раньше?
Так начинается история, из которой стало ясно: путь к идеальной ML-песочнице начинается не с Kubernetes-кластера, а с понимания того, что именно ты строишь и зачем.
Вернёмся к проблемам, с которыми сталкиваются ML-инженеры.
Окружение. Подготовка среды часто занимает не пару дней, а недели. При открытии новой ветки внутри компании или проекта каждой команде требуются свои Kubernetes-кластеры и ресурсы, а без изначальной автоматизации всё снова разворачивается вручную. В итоге процесс, который должен занимать пару дней, растягивается до двух–четырёх недель.
Утилизация GPU. Чем она выше, тем лучше. За каждую GPU-карточку в облаке платят по полной стоимости, независимо от загрузки, поэтому важно использовать ресурсы максимально эффективно. В идеале утилизация должна стремиться к 100%, но на практике это, конечно, недостижимо, и без продуманного мониторинга часть ресурсов просто простаивает.
Среднее время восстановления (MTTR). Из-за отсутствия пайплайнов, версионирования моделей, устойчивой инфраструктуры и централизованных инструментов каждая новая итерация модели вносит хаос: теряются веса, гиперпараметры и артефакты, а повторное обучение превращается в очередной квест. Время на откат растёт в разы. А после сбоя — измеряется уже днями, а не часами.
Воспроизведение и деплой. На ноутбуке у ML-инженера всё работает идеально, а в тестовом окружении и проде — рушится. Это знакомо многим: разница в средах, ручные действия, случайные правки перед релизом делают процесс непредсказуемым. Примерно треть экспериментов невозможно воспроизвести на проде.
Какой же должна быть песочница, чтобы наш герой с этими проблемами не столкнулся?
Какой стек нужен, чтобы собрать крепкий скелет ML-платформы

Базовая точка отсчёта. Есть четыре основных подхода к развёртыванию k8s: Kubeadm, Kubespray, KaaS в облаке, вендорские решения.
Каждый вариант — про разное, но имеются и пересечения.

Kubeadm — для энтузиастов и DevOps-гуру. Это надёжный, но трудоёмкий вариант: всё делается вручную, зато полный контроль и гибкость. Такой подход — для опытных инженеров, готовых тратить время на поддержку и настройку. Из коробки нет буквально ничего. Если у вас будет два пода, которым надо как-то базово между собой взаимодействовать, то не выйдет — ведь не будет даже CNI для работы сети в этом кластере.

Kubespray — подходит любому DevOps-инженеру и даёт чуть больше автоматизации: есть CNI, рантайм и большое сообщество. Но всё равно многое придётся делать вручную, а ещё нет поддержки российских ОС. Поэтому чтобы развернуть k8s через Kubespray, например, на Astra OS, придётся писать костыли для Ansible самостоятельно.

KaaS (k8s as a Service) — это скорость, поддержка и удобство, но не все сервисы доступны «из коробки», многое зависит от конкретного облачного провайдера. У каждого облака — свой доступный набор инструментов.
Коробочные вендорские решения — самые дорогие, но и самые production-ready решения: высокая скорость развёртывания, поддержка, интеграция, встроенный мониторинг и безопасность.
Пример такого решения — NOVA, почти всё есть в формате из коробки: мониторинг, логирование, безопасность, сетевая подсистема, скейлинг и так далее. Как раз ниже на картинке приведен технологический стек, согласитесь, «из коробки» есть гораздо больше сервисов, чем у того же kubespray.

На данном этапе мы только готовим инфраструктуру для нашей ML-модели, но выбор правильного инструмента для развёртывания k8s может существенно сократить путь к непосредственной работе с ML-моделью. Если вы выбираете вендорское решение, то платите много денег, но не тратите недели на интеграцию базовых вещей друг с другом.
Строим «песочницу»
Перейдём к практике: как построить песочницу для ML-моделей внутри Kubernetes и не утонуть в ручной рутине. Я разделяю платформу на уровни.
Аппаратный, он даёт драйверы, сеть и хранилище:
NVIDIA GPU Operator — автоматическая установка/обновление драйверов и runtime для GPU.
NVIDIA Network Operator — настройка высокопроизводительной сети (RDMA/RoCE).
Longhorn — отказоустойчивое блочное хранилище для PVC подов.
Этот слой обеспечивает базу для дальнейших сервисов: без него нельзя гарантировать работу GPU-задач, стабильную сеть и персистентные данные.
NVIDIA GPU Operator — сервис, который автоматизирует весь «низкий» слой для работы GPU в Kubernetes: ставит совместимые драйверы, NVIDIA Container Toolkit (runtime), device plugin и dcgm-exporter для метрик. В результате узлы с видеокартами становятся готовыми к запуску подов, использующих GPU, без ручной сборки окружения.
Оператор использует компонент Node Feature Discovery (NFD), который предварительно сканирует ваш bare metal хост, определяет компоненты внутри — наличие GPU и сетевых infiniband карт, их модели и вешает соответствующие лейблы, подтягивает нужные компоненты. Примерно так это выглядит логически: «обнаружена T4 → проставили метки на ноду → установили совместимые драйверы и плагин».
Если ваша операционная система не входит в поддерживаемые (или отличается по критичным пакетам/ядру), автоустановка может не сработать: не будут совпадать метки, не подтянутся правильные образы, драйвер не соберётся модулем. Тогда остаются два пути:
собрать контейнеры/образы с драйверами самостоятельно;
установить драйверы вручную на узел и скорректировать конфигурацию GPU-оператора до деплоя в k8s-кластера.
С dcgm-exporter вы получаете метрики загрузки и состояния GPU (для Prometheus/Grafana), что помогает контролировать утилизацию и искать узкие места ваших GPU и базовые метрики вроде температуры и утилизации.
Оператор поддерживает несколько подходов к разделению ресурсов GPU, но нас интересуют лишь два основных подхода:
Time-Slicing — временные квоты без строгой аппаратной изоляции. Подходит, если нужно «поделиться» GPU между несколькими подами и вы готовы к конкуренции за ресурсы.
MIG (Multi-Instance GPU) — аппаратные «слайсы» с предсказуемой производительностью и изоляцией. Доступно на картах поколения Ampere и новее (минимум, A30).
NVIDIA Network Operator — опциональный, но важный компонент. Это дополнительный сервис, который отвечает за настройку и оптимизацию сетевой подсистемы при работе с GPU. Он не обязателен для базового запуска Kubernetes-кластера под ML-нагрузки, но становится критичным, если вы работаете с тяжёлыми ML-моделями, распределённым обучением или большими объёмами данных.
Главная цель оператора — повысить пропускную способность сети и снизить задержки за счёт использования протоколов InfiniBand и RoCE (RDMA over Converged Ethernet). Это особенно важно, например, для задач, когда модель не помещается на одной видеокарте и требуется быстрая межузловая коммуникация.
По сути, Network Operator выполняет те же функции, что и GPU Operator, но в сетевом контексте:
автоматически устанавливает драйверы и компоненты RDMA с теми же ограничениями по ОС, что и у GPU-оператора. Не все дистрибутивы Linux официально поддерживаются, и при нестандартных системах драйверы придётся собирать вручную.
настраивает сетевые плагины и интерфейсы под Kubernetes.
Также он дает две ключевые функции:
GPU Direct RDMA (Remote Direct Memory Access) — позволяет объединять физические GPU (например, A100) в единый k8s-кластер, где данные передаются напрямую между видеокартами, минуя процессор. Это даёт возможность обучать очень большие модели, не умещающиеся на одной карте.
GPU Direct Storage (GDS) — обеспечивает прямой доступ GPU к NVMe-дискам без участия CPU и системной памяти. Это резко ускоряет загрузку данных при обучении, устраняя узкое место в I/O и повышая общую производительность.
Longhorn — это отказоустойчивое распределённое блочное хранилище, которое управляется через Kubernetes и позволяет гибко конфигурировать пространство на хостах и динамически выделять тома для подов. Он распределяет данные по нескольким хостам, обеспечивая высокую доступность и автоматическое восстановление в случае сбоя узла.
Longhorn решает задачу хранения артефактов, ML-моделей, датасетов и любых других данных, с которыми работают инженеры. Вместо того, чтобы вручную подключать диски, данный сервис автоматически создаёт и монтирует необходимые тома. Это избавляет команду от ручной работы и гарантирует, что данные не потеряются при перезапуске подов или выходе ноды из строя при корректной настройке данного сервиса.
Начиная с версии 1.8, Longhorn использует новый движок v2, оптимизированный под работу с NVMe-дисками. Это повышает скорость операций ввода-вывода и общую производительность хранения — особенно при обучении ML-моделей, где критичны скорость доступа и стабильность.
Как это выглядит на практике?

Предположим, у вас уже есть Kubernetes-кластер — либо готовый, либо только на этапе развертывания — и три физических железных хоста с GPU и локальными дисками.
Подключение узлов. Сначала вы устанавливаете Kubernetes и добавляете эти хосты как worker-ноды к Kubernetes-кластеру.
-
Развёртывание операторов. После этого устанавливаются необходимые операторы — GPU Operator, Network Operator. Они автоматически сканируют железо:
Компонент Node Feature Discovery (NFD) проходит по всем нодам, собирает информацию о железе (GPU, CPU, диски, сеть) и проставляет лейблы, по которым Kubernetes затем распределяет поды. Это даёт системе понимание, какие ресурсы доступны и куда можно планировать задачи с GPU или высокоскоростным хранилищем.
GPU Operator определяет модели видеокарт, устанавливает драйверы и другие необходимые компоненты, перечисленные ранее;
Network Operator настраивает сетевые интерфейсы и RDMA;
Настройка хранилища. После этого вы разворачиваете Longhorn. Он создаёт распределённое хранилище между вашими, в данном случае трёмя, хостами. Все сервисы, которым нужно физическое пространство — будь то артефакты, данные ML-моделей или датасеты, — получают доступ к томам через Longhorn.

Уровень хранилищ

Следующий уровень — уровень хранилищ, который объединяет три основных компонента: MinIO, PostgreSQL и Gitea.
Достаточно всем знакомые компоненты, но давайте рассмотрим, как они работают в контексте нашей платформы:
MinIO используется как объектное хранилище для датасетов, ML-моделей, артефактов модели и других данных — как сырых, так и предварительно обработанных. Это центральная точка доступа для всех сервисов: откуда можно брать и куда складывать артефакты моделей.
PostgreSQL отвечает за хранение служебной информации — метаданных сервисов, рабочих процессов, задач и параметров выполнения. Почему именно PostgreSQL? Потому что это единственная база данных, которая нативно интегрируется со всеми сервисами платформы. Мы проводили исследование по выбору production-ready решения в open source, и Zalando PostgreSQL-оператор показал себя оптимально: он прост в установке, гибко настраивается и хорошо работает в Kubernetes, в том числе при интеграции с S3 и балансировщиками.
Gitea используется как внутренний репозиторий для хранения кода, конфигураций и пайплайнов, что упрощает версионирование и интеграцию с CI/CD процессами.
Сервисный слой

Следующий уровень — сервисный слой, в который входят три ключевых компонента: Apache Airflow, MLflow и KServe. Они уже не такие типичные и именно они превращают нашу k8s-инфраструктуру в полноценную ML-платформу, где можно управлять пайплайнами, экспериментами и развёртыванием ML-моделей.
Apache Airflow — это мощный оркестратор задач, который можно считать сердцем всей платформы. Он управляет последовательностью действий через так называемые DAG’и (Directed Acyclic Graphs) — графы задач, описывающие, что, в каком порядке и где должно быть выполнено Airflow. Как раз DAG’и лежат в Gitea, с которой Airflow периодически синхронизируется через контейнер git-sync.
Примерно это выглядит так:
«Возьми датасет из MinIO → запусти обработку данных → запусти обучение ML модели → сохрани артефакты → сделай запуск stage по инференсу модели».
Airflow интегрируется с Kubernetes и для каждой задачи запускает отдельный под через тот оператор, который был выбран пользователем для его задачи, например, KubernetesPodOperator (на самом деле их, конечно, больше - более подробно можно ознакомиться в документации)
MLflow — это open-source фреймворк для управления жизненным циклом ML-моделей: от экспериментов, реестра моделей до регистрации моделей в прод. Он включает в себя четыре ключевых компонента:
Tracking — отслеживание экспериментов, гиперпараметров и метрик;
Projects — определение и воспроизводимость сред выполнения;
Models — реестр версий моделей;
Registry — хранение, утверждение и публикация моделей для последующего использования.
MLflow тесно интегрируется с остальными сервисами платформы. Инженеры могут отслеживать все этапы обучения, анализировать результаты и централизованно управлять артефактами. Это напрямую решает одну из ключевых проблем, озвученных ранее — потерю гиперпараметров и невозможность воспроизвести эксперименты. Также пользователи могут удобно сравнить результаты экспериментов между собой, просто выбрав необходимые, и, например, как-то пометить через теги более «удачный» эксперимент.
KServe отвечает за развёртывание и масштабирование ML-моделей в Kubernetes. Это компонент, который автоматизирует весь процесс инференса: от подготовки окружения в k8s до создания эндпойнта модели.
Главн��я идея — инженер описывает модель всего в одном YAML-файле (пример такого файла посмотрим в следующем разделе практики), указывая:
фреймворк (например, PyTorch, TensorFlow, Sklearn, vLLM);
путь к артефакту модели в S3/MinIO или к registry с контейнером;
ресурсы (GPU, CPU, память);
параметры инференса и сетевые настройки.
После применения манифеста KServe автоматически создаёт все необходимые сущности — Deployment, Service, InferenceService — и поднимает endpoint, доступный для запросов к ML-модели. При этом под капотом KServe использует готовые образы популярных фреймворков, что исключает необходимость ручной настройки контейнеров.
Дополнительно в KServe есть секция Transformer — она позволяет описать pre- и post-processing данных. Например, можно заранее преобразовать изображение перед подачей в модель или разметить результаты инференса после получения ответа. Итог: инженер кладёт модель в хранилище, описывает её в YAML-файле — и примерно через несколько минут (в зависимости от того что он деплоит) получает работающий endpoint, за которым скрыты все базовые сущности в Kubernetes. В базовом варианте это нужно было делать вручную.
Интерфейс

Завершает архитектуру нашей песочницы JupyterHub — многопользовательский сервер, который позволяет запускать Jupyter Notebook буквально в один клик. JupyterHub идеально подходит для ML-инженеров, аналитиков и дата-сайентистов, которым важен быстрый доступ к интерактивной среде. Всё, что им требуется — браузер. Не нужно устанавливать Python, пакеты, драйверы или решать проблемы совместимости: окружение создаётся централизованно и одинаково для всех пользователей.
JupyterHub разворачивается поверх Kubernetes и создаёт изолированные контейнеры для каждого пользователя. Это позволяет:
запускать ноутбуки с заданными ресурсами (CPU, GPU, память);
управлять версиями окружения;
интегрировать рабочие сессии с внутренним хранилищем и репозиторием кода (например, MinIO или Gitea).
Стандартный образ ноутбука не включает в себя гитлаб-плагин, чтобы сделать его удобнее, необходимо пересобрать контейнер и доустановить в него необходимые пакеты git и jupyterlab-git.
JupyterHub — это своего рода вишенка на торте всей ML-песочницы. Он является такой единой точкой входа, где инженер просто открывает браузер, запускает ноутбук и начинает писать код, не задумываясь о том, где это всё крутится в инфраструктуре.
Архитектура ML-песочницы: как всё связано между собой

На этом этапе платформа уже объединяет все ключевые компоненты — от железа до сервисов и инструментов разработчика. Теперь важно понять, как они взаимодействуют между собой.
Интеграция с внешними системами
В большинстве компаний уже есть собственная инфраструктура:
registry для хранения контейнеров (например, Harbor или GitLab Container Registry),
GitLab или Gitea для хранения кода DAG’ов,
S3-совместимые хранилища для данных и артефактов.
Все эти элементы можно интегрировать в ML-платформу. Платформа не изолирует существующие ресурсы, а наоборот — подключает их как внешние сервисы, обеспечивая единое управление и прозрачный обмен данными.

Архитектура условно разделена на три зоны, каждая из которых отвечает за свой уровень работы:
-
Инфраструктурная зона
Здесь расположены базовые сервисы:MinIO — объектное хранилище для датасетов и моделей,
PostgreSQL — база данных для хранения метаданных и служебной информации,
Longhorn — storage-сервис для выделения PVC подам.
Эта зона обеспечивает фундамент: хранение, устойчивость и консистентность данных.
-
Рабочая зона инженера
Здесь работают основные инструменты ML-разработки:Airflow — оркестрация пайплайнов,
MLflow — управление экспериментами и версиями моделей,
JupyterHub — централизованная работа в jupyter-ноутбуках DS/ML-инженерами.
Это — пространство, где инженер проводит исследования, обучает и тестирует модели, не покидая платформу.
-
Сервисная зона
Отвечает за контроль, мониторинг и доставку:FluxCD — GitOps-деплой и автоматизация поставки;
Harbor — registry для контейнеров;
Prometheus и Grafana — мониторинг и визуализация метрик;
Gitea — внутренний git-репозиторий (в данном случае зеркало для Gitlab) для пайплайнов и конфигураций;
KServe — взаимодействие с моделями, деплой и инференс.
Gitlab — внешний сервер для хранения пайплайнов/DAG
Здесь сосредоточены инструменты, которые следят за стабильностью и обновляемостью системы.
Поток данных в платформе устроен прозрачно и линейно — от обучения до продакшн-инференса:
Инженер потестировал что-то в JupyterHub и через Airflow запускает процесс обучения.
Данные и модели хранятся в MinIO, а метаданные и результаты экспериментов — в MLflow и PostgreSQL.
После обучения модель передаётся в KServe, где создаётся endpoint для инференса.
FluxCD отслеживает изменения и автоматически обновляет деплой.
Prometheus собирает метрики, а Grafana визуализирует состояние сервисов и ML-моделей.
На диаграмме всё это может выглядеть запутанно: множество стрелок, взаимосвязей и компонентов. Но на практике платформа работает как единый конвейер: от загрузки данных и обучения модели до развёртывания и мониторинга — всё проходит по предсказуемому и автоматизированному пути.
Практика от запуска обучения через Airflow до деплоя и инференса модели в k8s
Перейдём к практике и исходным условиям. Мы — интегратор с широкой экосистемой технологических партнёров. Как уже отмечалось, для полноценной ML-платформы недостаточно «затащить» только ML-сервисы: нужны также мониторинг, логирование, безопасность, реестры контейнеров, GitOps-поставка и т.д.
Чтобы сократить время на развёртывания и избежать лишней рутины, я взял платформу Nova, где ключевые сервисы уже идут из коробки. Это сняло массу головной боли и позволило быстрее выйти на рабочий минимум. При этом важно понимать: в таких платформах основа — open source k8s. Всё можно развернуть самостоятельно, но это займет заметно больше времени на установку и настройку различных интеграций.

В качестве воркеров я использовал два сервера Dell с GPU NVIDIA T4, а также внешний GitLab, зеркалом которого была Gitea для интеграции с Airflow. В демо-кейсе задача была простой и показательной: классифицировать изображения моего кота на базе датасета CIFAR-100 с помощью модели ResNet-18. Цель — пройти полный цикл без погружения в бэкенд в роли ML-инженера: подготовка данных, обучение, логирование метрик и артефактов, инференс ML-модели в мою демо-среду. С точки зрения инженера это сводилось к написанию нескольких Python-пайплайнов (stages) и сборке из них DAG для Airflow — платформенные компоненты делали всё остальное.

Всего в пайплайне было пять задач или стейджей, каждая отвечала за свой этап жизненного цикла модели: сбор и подготовка данных (fetch_data), обучение модели на датасете (train_model), проверка метрик и качества обученной модели (check_metrics), тестовый запуск модели на новых данных (infer_gradio). Последняя — utils.py— служебная задача-уведомление об окончании обучения моей ML-модели. Telegram-бот отправляет сообщение о завершении обучения и результатах.
Итак, всё просто: push — и код улетает в GitLab. Наши пайплайны версионируются в git-репозитории. После этого Airflow синхронизируется с Gitea, куда зеркалируется весь репозиторий. Через 10–20 секунд новый DAG автоматически подтягивается в Airflow и становится доступным для запуска.
В интерфейсе Airflow справа появляются action-кнопки — через них можно управлять задачами: запускать DAG вручную, ставить на паузу, пересоздавать определённые стадии или смотреть логи выполнения. В общем, можно настроить так, что всё будет работать без дополнительных ручных действий.

После старта первым создаётся под data_preparation — этап подготовки данных. На этом шаге:
выполняется выгрузка сырого дата-сета в S3-хранилище,
производится базовая предобработка: очистка, разметка, приведение формата, разделение на выборки.

После завершения этапа подготовки данных Airflow автоматически переходит к следующей стадии DAG — обучению модели.

Запускается новый под, в котором происходит цикл обучения: установка зависимостей, инициализация окружения (например, загрузка библиотек PyTorch или TensorFlow) и запуск основного скрипта, написанного мною для демо. Процесс занял в среднем 7–10 минут, но это, конечно, зависит от объёма данных и мощности GPU.

В процессе работы под логирует всё — от загрузки данных до расчёта метрик — а результаты (веса модели, артефакты и логи) сохраняются в S3-хранилище и postgresql. А на картинке ниже вы можете видеть, как в поде ставятся необходимые пакеты для выполнения задачи.

На картинке ниже представлен граф DAG в интерфейсе Apache Airflow — визуальное отображение всех стадий пайплайна.
Если рассматривать его подробнее, то можно увидеть следующее:
полный список задач (стейджей) и их последовательность;
текущие статусы выполнения (в ожидании, выполняется, успешно завершено, ошибка);
на базе каких операторов выполняются задачи (например, PythonOperator);
возможность перейти в логи каждой стадии для анализа деталей выполнения.
Если какая-то стадия завершилась с ошибкой, Airflow позволяет точечно перезапустить только её, не проходя заново весь конвейер. Это удобно при отладке или повторных экспериментах.

Когда обучение завершается, система автоматически переходит к следующему шагу — проверке метрик.
Airflow запускает новый pod, который оценивает, соответствуют ли полученные результаты (например, accuracy и loss) заданным порогам. Если метрики удовлетворяют условиям, пайплайн продолжает выполнение и переходит к этапу инференса.
В демонстрационном сценарии я заранее задал необходимые параметры после обучения, чтобы не тратить время на дополнительную оптимизацию. На этапе инференса модель тестируется на новых данных, в данном случае это будет фотография моего кота, и мы убеждаемся, что она корректно работает в реальных условиях.
Если же метрики не достигают целевых значений (что иногда случалось во время тестов), этап инференса пропускается, пайплайн завершает работу, а я возвращался к доработке параметров модели.

https://github.com/kserve/kserve
Перед тем как перейти непосредственно к инференсу модели через Kserve, давайте разберёмся, как заполнить манифест InferenceService — ключевой компонент, отвечающий за развёртывание модели в Kubernetes (см. картинку выше).
Давайте еще раз посмотри, что нужно, чтобы его применить. Во-первых, необходимо создать заранее две сущности в Kubernetes-кластере, если их еще нет:
Secret — хранит учётные данные для доступа к S3-хранилищу (MinIO), где лежит обученная модель и артефакты.
ServiceAccount — сервисный аккаунт, который привязывается к этому Secret и используется для аутентификации подов при работе с S3.
После этого можно описывать сам InferenceService в виде YAML-манифеста.
В нём указываются:
путь к модели в s3;
используемый inference-backend (например, Triton);
параметры ресурсов (GPU, CPU, RAM);
а также аннотации, где прописаны ссылки на Secret и нужный сервисный аккаунт.
После применения манифеста KServe создаёт под капотом все необходимые сущности k8s: Deployment, Service, Pod и связанные конфигурации.
Я выбрал Triton в качестве backend, указал его версию, задал путь к модели в S3, а также прописал ресурсные параметры — requests и limits, выделив под задачу одну GPU-карту.
После применения манифеста модель успешно задеплоилась: в Kubernetes появились два пода.
Первый — это под, в котором выполняется сам ML-инференс.
Второй — под с Gradio, лёгкий Python-фреймворк, который разворачивает веб-интерфейс для тестирования модели.
Gradio позволяет создать тестовый WEB-интерфейс, кнопку загрузки и увидеть результат работы модели (выглядит это примерно как на картинке ниже).

Знакомьтесь — это мой кот Мелкумян. Именно на нём я решил проверить, как работает модель. Я загрузил его фотографию в интерфейс Gradio и задал у себя в голове простой вопрос: «Что модель видит на этом изображении?» ииииии, барабанная дробь, модель увидела «камбалу». Да, звучит странно и смешно, но в её защиту скажу: кот действительно очень худой, так что ошибка частично объяснима.
Как я и говорил ранее, цель демо была не в максимальной точности модели, а в показе полного цикла — от обучения до деплоя и инференса. Если бы я использовал более подходящий датасет или обучал дольше, модель, вероятно, безошибочно определила бы объект.

В интерфейсе MLflow удобно просматривать и сравнивать результаты экспериментов.
Слева видны две таблицы:
первая содержит метрики (например, accuracy, loss, precision и recall),
вторая — параметры обучения (количество эпох, размер батча и т.д.).
Эти данные автоматически регистрируются при запуске пайплайна на конкретной стадии. MLflow позволяет легко сравнивать итерации: можно открыть две версии модели, увидеть, как изменились метрики, и быстро понять, какие параметры стоит подкорректировать — например, увеличить число эпох.
Справа на слайде показано уведомление в Telegram (как раз тот самый utils.py), которое приходит после завершения обучения. В нём указано:
название модели,
параметры/эпохи запуска,
ключевые метрики.
При необходимости можно перейти по ссылке прямо из уведомления в конкретный Run ID в MLflow, чтобы посмотреть детали эксперимента, логи и артефакты.
Результаты или почему песочница — идеальная

Почему я называю эту песочницу идеальной? Ответ прост — она действительно ускоряет и упрощает работу команды.
Время до первого демо (time-to-first-demo) сократилось в 5–7 раз. Теперь первые результаты обучения и инференса можно увидеть через пару дней, а не через недели, как раньше.
Онбординг нового инженера стал значительно быстрее. Раньше погружение в проект могло занимать месяцы: настройка окружения, поиск данных, разбор зависимостей. Теперь это занимает пару дней — благодаря прозрачной инфраструктуре, понятной структуре зон и готовым инструментам. Как я уже отмечал, у нас есть чёткое разделение по средам для работы.
Утилизация GPU выросла на 30–40% благодаря использованию технологий MIG (Multi-Instance GPU) и time-slicing, доступных «из коробки» в NVIDIA GPU Operator. Эти механизмы позволяют эффективно делить ресурсы видеокарты между задачами. В результате время простоя GPU снижается почти вдвое, и вычислительные мощности используются максимально эффективно. Это напрямую влияет на экономику проекта: меньше неиспользо��анных карточек — меньше лишних расходов.
Цикл от эксперимента до продакшн-эндпойнта сократился примерно в три раза. Раньше на это уходили недели: подготовка среды, ручной деплой, тестирование. Теперь большинство процессов автоматизировано — инфраструктура создаётся через KServe InferenceService, а инженеру достаточно описать модель в одном YAML-файле. Все скрытые сущности (под, сервис и прочие) создаются автоматически, что радикально ускоряет поставку результатов. Кроме того, все эксперименты централизованно отслеживаются в MLflow. Инженеры могут сравнивать метрики разных запусков, анализировать параметры и находить оптимальные конфигурации ML-моделей. Это повышает прозрачность, воспроизводимость и качество исследований.
Благодаря DCGM-экспортеру из GPU Operator можно следить за состоянием видеокарт: температурой, утилизацией, производительностью, возможными узкими местами. Все эти данные собираются в Prometheus и визуализируются в Grafana, что позволяет сократить время обнаружения инцидента с часов до минут.
В итоге, за счёт прозрачного конвейера и автоматизированного флоу, скорость релизов ML-пайплайнов увеличилась на 60–70%. Команда получает предсказуемые, стабильные результаты, а эксперименты становятся не только быстрее, но и значительно понятнее для анализа и масштабирования.
Все имеющиеся вопросы по содержанию статьи можно задать в комментариях под статьей либо мне в Telegram: https://t.me/DV_Salman