Привет! Я Дмитрий, инженер и руководитель направления MLOps в Совкомбанке. Специализируюсь на разработке и эксплуатации ML-платформ на базе Kubernetes и GPU.
С 2010 года в ИТ: строю инфраструктуру для машинного обучения, внедряю Kubeflow и GPU-оператор, настраиваю MIG на H100 в корпоративных средах с повышенными требованиями к безопасности и надежности. В последние годы фокусируюсь на оптимизации ML-пайплайнов, повышении утилизации GPU (включая MIG-профили) и интеграции MLOps-практик в процессы продуктовых команд.
В 2022 году в некоторых командах разработки «Совкомбанка» уже существовали проекты с применением искусственного интеллекта. Это были отдельные компоненты, которые хорошо справлялись с конкретными задачами приложения. Но не хватало единой платформы управления.
По мере роста количества и сложности бизнес-задач возникла необходимость в создании ML-платформы как сервиса с едиными стандартами авторизации, размещения моделей на платформе для устранения проблем контроля, унификации и безопасности ML-моделей.
Единая ML-платформа с гибким RBAC позволила бы:
-
Защитить модели и данные — с контролем доступа на уровне команд и проектов.
-
Отслеживать, кто и когда использует модель — для аудита и безопасности.
-
Дать бизнесу самостоятельность — без ожидания инженеров, можно быстро тестировать гипотезы.
Мы изучили доступные инструменты, попытались объединить их в одном Kubernetes-кластере, столкнулись с рядом ограничений — и в итоге пришли к архитектуре на базе Kubeflow и GPU-оператора.
В статье рассказываем, какие сложности были в ходе проекта, как выстроили работу с Kubeflow, настраивали H100 с MIG-разделением и что важно учесть, если вы планируете строить ML-платформу на bare-metal-GPU в корпоративной среде.
Что внутри
На рынке в то время были доступны две ML-платформы: проприетарная Caila от Just AI и open-source-решение Kubeflow.
Оба варианта предъявляли схожие требования к инфраструктуре:
-
кластер Kubernetes последних версий;
-
bare-metal-серверы с поддержкой GPU;
-
административные привилегии в кластере.
Для управления кластерами Kubernetes в банке используется платформа «Штурвал», обладающая модульной и расширяемой архитектурой. Большая часть необходимых модулей работала в платформе «из коробки» — и то, что нам потребовалось доработать, никак не повлияло на поддержку решения. Для вычислительных ресурсов выбрали доступные на тот момент bare-metal-серверы с GPU H100.
Сначала мы развернули коммунальный Kubernetes-кластер для обеих ML-платформ. Разделение микросервисов планировалось осуществлять по стандартной схеме с использованием labels и taints для изоляции компонентов разных платформ. Однако этот подход привел к ряду критических проблем:
-
Конфликты компонентов. Несмотря на использование labels и taints, компоненты Caila и Kubeflow конфликтовали при работе в одном кластере. ML-платформы конкурировали за ресурсы одних и тех же серверов. Распределить их компоненты между разными серверами не удалось, так как у производителей нет такой возможности. Любое обновление компонента платформы приводило бы к изменению конфигурации и откату назад. Из-за этого было сложно применить единую схему маркировки ко всем Kubernetes YAML-манифестам, которые генерировали платформы.
-
Угрозы информационной безопасности. Обе платформы имели административные привилегии в кластере и, следовательно, получали доступ ко всем компонентам друг друга. Это создавало потенциальные риски для безопасности и изоляции данных.
В результате анализа этих проблем мы решили разделить проекты на два независимых кластера.
Создание и настройку кластера Kubernetes в данной статье опустим, в «Штурвале» это делается просто и быстро. Сфокусируемся на самом интересном — установке Kubeflow и настройке видеокарт.
Установка Kubeflow в кластере
Необходимые компоненты:
-
Три виртуальных мастера на RedOS с ядром 6.12.21.
-
Три железных рабочих ноды на RedOS с ядром 6.12.21 и видеокартами H100.
-
Собранный кластер на «Штурвале».
Ниже описываем, как пошагово установить и настроить драйверы в любом используемом дистрибутиве Kubernetes.
-
Закомментируем в /etc/dnf/dnf.conf
exclude=kernel* *kernel -
Ставим пакет для ядра.
yum install kernel-lt-devel-6.12.21.red80.x86_64 -
Проверяем, что в параметрах grub установлены эти значения:
module.sig_enforce=0rd.driver.blacklist=nouveau -
Добавляем драйвер nouveau в blacklist-модулей.
Создаем файл
/etc/modprobe.d/blacklist-nouveau.conf:Скрытый текст
После перезагрузки вывод следующей команды должен быть пустым:
lsmod | grep nouveauЕсли это не так, выполняем следующую команду и перезагружаемся:
dracut –force -
Отключаем /etc/dnf/plugins/subscription-manager.conf
Далее выставляем флаг
disable_system_repos=0 -
Включаем прокси.
export https_proxy=http://proxy.company.io:3128/ export http_proxy=http://proxy.company.io:3128/ -
Подключаем два репозитория:
Создаем в
/etc/yum.repos.d/cuda-rhel8.repo:Скрытый текст
nvidia-container-toolkit.repo:Скрытый текст
Обязательно включаем репозитории: enabled=0 меняем на enabled=1
-
Устанавливаем драйверы.
dnf install dkms dnf -y module install nvidia-driver:latest-dkms -
Проверяем наличие драйвера
modprobe -vv nvidia lsmod | grep nvidiaили
nvidia-smi -
Включаем службу.
systemctl enable --now nvidia-persistenced.service -
Ставим дополнительные пакеты.
yum install nvidia-docker2.noarch yum install nvidia-fabric-manager-580.95.05.x86_64 -
Перезагружаемся и проверяем, что все работает корректно.
reboot nvidia-smi
Подводные камни
Во время установки пользователи могут столкнуться с рядом ошибок, которые мы решали совместно с инженерами «Штурвала». Ниже разберем самые распространенные и возможные пути их решения.
-
После установки драйвера, модуль ядра не подгружается
При попытке выполнить
modprobe nvidia, система выдает вот такую ошибку:Required key not availableРешение:
-
DKMS не видит драйверы
При наборе команды:
dkms status
вместоinstalled:nvidia/580.95.05: addedСобираем и устанавливаем драйвер с помощью dkms:
sudo dkms install -m nvidia -v 580.95.05Если система выдает подобную ошибку:
Failed command: 'make' -j128 KERNEL_UNAME=6.12.21.red80.x86_64 modules Error! Bad return status for module build on kernel: 6.12.21.red80.x86_64 (x86_64)Смотрим логи:
cat /var/lib/dkms/nvidia/580.95.05/build/make.logВидим ошибку прав доступа у системного линкера:
/bin/sh: line 1: /bin/ld: Permission deniedДалее смотрим права линкера:
ls -l /usr/bin/ldУдаляем файл и создаем символическую ссылку:
sudo rm -f /usr/bin/ld sudo ln -s /usr/bin/ld.bfd /usr/bin/ldПовторно собираем и устанавливаем драйвер:
sudo dkms install -m nvidia -v 580.95.05 dkms status -
Если под nvidia-operator-validator не стартует с версией драйверов 580.95.05 из официального репозитория nvidia, то читаем логи пода.
Если видим подобную ошибку:
Скрытый текст
Error: failed to create containerd task: failed to create shim task: OCI runtime create failed: runc create failed: unable to start container process: error during container init: error running prestart hook #0: exit status 1, stdout: , stderr: Auto-detected mode as 'legacy' nvidia-container-cli: mount error: failed to add device rules: unable to generate new device filter program from existing programs: unable to create new device filters program: load program: invalid argument: last insn is not an exit or jmp processed 0 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0: unknownТо решаем ее путем изменения параметров ядра:
с net.core.bpf_jit_harden=2наnet.core.bpf_jit_harden=1Настраиваем nvidia container toolkit:
Скрытый текст
Настраиваем конфиг containerd в
/etc/containerd/config.tomlВ секции
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes]меняем значения для runtime в подсекциях:Скрытый текст
В подсекции
[plugins."io.containerd.runtime.v1.linux"]меняем значение наruntime = "nvidia"
Разворачиваем gpu-operator в кластере
-
Перед деплоем gpu-operator необходимо добавить namespace (gpu-operator) в исключение kyverno
-
Далее качаем helm chart и добавляем в проект кластера. Описание helm values доступно здесь.
-
Отключаем лишнее в values (драйвер ставим самостоятельно):
Скрытый текст
Указываем mig strategy в mixed:
mig: strategy: mixedДобавляем (fix bug) в validator:
Заносим параметры в tolerations:
-
Запускаем pod для теста:
Смотрим логи:
kubectl apply -f cuda-vectoradd.yaml kubectl logs pod/cuda-vectoraddВот так выглядит корректный ответ:
Скрытый текст
После удаляем pod:
kubectl delete -f cuda-vectoradd.yaml
Делим GPU с помощью MIG
MIG (Multi-Instance GPU) в Kubernetes — это функция разделения графического процессора (GPU) на аппаратном уровне. MIG позволяет разделить один GPU на несколько изолированных экземпляров, каждый из которых имеет выделенные вычислительные ядра, память и кэш.
Эта функция полезна, когда у рабочих нагрузок разные требования к ресурсам и нужно обеспечить строгую изоляцию между ними.
Сейчас пошагово расскажем, как с этим работать.
-
Разбиваем GPU на отдельные виртуальные части mig, чтобы получить:
Изоляцию ресурсов
Каждая MIG-инстанция работает независимо — как отдельная GPU. Нет «шумных соседей» — если один под грузит GPU — другие не страдают. Изоляция на уровне железа, а не софта (как в контейнерах).
Максимальную утилизацию GPU
Вместо одной тяжелой задачи — можно запустить несколько легких. Например: A100 40GB → 7 MIG 1g.10gb → 7 задач inference.
Гарантированную производительность
Каждая MIG получает фиксированный объем памяти и вычислительных ядер. Идеально для inference-задач, где нужна предсказуемая задержка.
Безопасность
Изоляция на уровне железа — даже если один под «сломается», другие продолжат работать. Это отлично подходит для мультитенантных сред, где разные команды/проекты используют одну GPU.
Поддержку ML/DL/Inference
Идеально для inference, batch processing, ML pipelines. Не подходит для heavy training — там лучше использовать целую GPU.
-
Работа с MIG
Так как уже развернут gpu-operator со стратегией “mig strategy: mixed” и точно известно, что карты поддерживают разделение на MIG, важно выполнить несколько шагов, чтобы разбить имеющиеся у нас карты.
Первым делом смотрим доступные GPU на нодах:
kubectl get node -o json | jq '.items[].metadata.labels'Меняем профиль MIG на ноде (all-1g.10gb или all-1g.20gb — профиль, необходимо выбрать подходящий):
kubectl label nodes $NODE nvidia.com/mig.config=all-1g.10gb --overwriteМожем изменить профиль на сбалансированный, то есть разбить всю карту на части разных размеров:
kubectl label nodes <node-name> nvidia.com/mig.config=all-balanced --overwriteПри желании отключить MIG на ноде вводим эту команду:
kubectl label nodes $NODE nvidia.com/mig.config=all-disabled --overwriteДля того чтобы посмотреть список профилей MIG’ов, достаточно на ноде с GPU выполнить:
nvidia-smi mig -lgipЗапускаем поды с MIG — для этого указываем в манифесте следующее:
Если нужен конкретный MIG-инстанс, даем больше информации:
Далее проверяем корректность работы с помощью команды.
kubectl get pods -o jsonpath='{range .items[]}{.metadata.name}{"t"}{.spec.containers[].resources.limits}{"n"}{end}'Если вы все сделали правильно, то на выходе получаете такой ответ:
my-pod-1 map[nvidia.com/mig-1g.10gb:1] -
Принципы и примеры разбиения на MIG.
Существует несколько подходов:
-
По нагрузке — меняем объем GB: MIG 1g.10gb или MIG 2g.20gb.
-
По количеству задач — меняем цифру в начале: 4 MIG 1g.10gb. или 2 MIG 2g.20gb.
-
По вычислительной мощности — изменяем количество ядер: 1g → 1/7 ядер, 2g → 2/7 ядер
-
По типу задач:
Inference — 1g.10gb
Training — 7g.40gb
Batch processing — 2g.20gb -
По изоляции — при работе с критичными задачами важно выделить отдельную MIG.
-
По стоимости: MIG дешевле, чем целая GPU.
Примеры разбиения:
H100 80 GB:
-
14 MIG 1g.10gb (для inference)
-
4 MIG 2g.20gb (для training)
-
2 MIG 4g.40gb (для heavy training)
-
1 MIG 7g.80gb (для super-heavy training)
4. Недоступность MIG
Поды не могут переопределить MIG, если одна MIG становится недоступна, так как это физическая изоляция.
Что же происходит, если MIG недоступна:
-
Под не запускается — то есть Kubernetes не может выделить MIG.
-
Pod переходит в состояние Pending, пока не освободится MIG.
-
Восстановление реализуется через livenessProbe, readinessProbe, HorizontalPodAutoscaler.
Есть несколько доступных механизмов, позволяющих обойти это:
-
Failover. Можно переключиться на другую GPU, например, на GPU 1.
-
Circuit Breaker. Не нужно работать с MIG, если она недоступна. Если inference-сервис не отвечает, стоит переключиться на резервный.
-
Retry с экспоненциальной задержкой через 1s, 2s, 4s, 8s.
5. Планирование разбиения на MIG.
Для начала необходимо определить, какие задачи будут запускаться, и ответить себе на несколько вопросов:
-
Сколько нужно памяти и вычислительных ресурсов?
-
Какие MIG-инстанции доступны и сколько MIG можно создать?
-
Сколько задач могут запускать одновременно?
-
Нужна ли изоляция между задачами? А гарантированная производительность?
-
Какие метрики, логи, трейсы, дашборды важны для MIG?
-
Что важно учесть в CI/CD?
-
Деплой kubeflow 1.10
-
Для работы kubeflow необходимы cert-manager и istio, которые есть в репе с Kubeflow.
А для создания деплоя на джамп-хост необходимо установить kustomize и yq.
-
Первым делом клонируем проект:
-
Устанавливаем kubeflow в кластер по инструкции на странице проекта по адресу https://github.com/kubeflow/manifests с помощью kustomize.
-
Пропускаем установку cert-manager, так как он уже присутствует в кластере «Штурвала».
Поэтому устанавливаем только cert-manager-kubeflow-Issuer.
Istio устанавливаем, как указано для oauth-proxy, а oauth-proxy устанавливаем для dex.
-
Создаем файл ingress с типом сервиса istio-ingressgateway и названием ingress.yaml:
Пример манифеста
ingress.yamlпредставлен ниже (вместо переменных$clusternameи$envподставьте свои значения):Скрытый текст
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: annotations: name: ingress-kubeflow namespace: istio-system spec: ingressClassName: nginx rules: - host: kubeflow.apps.k8s-$clustername-$env.company.io http: paths: - backend: service: name: istio-ingressgateway port: number: 80 path: / pathType: Prefix tls: - hosts: - kubeflow.apps.k8s-$clustername-$env.company.io -
Применяем манифест командой
kubectl apply -f ingress.yaml -
Kubeflow состоит из множества компонентов и разворачивается довольно долго. В процессе деплоя возможно появление различных ошибок, во всяком случае у нас они постоянно появлялись, которые необходимо будет дебажить по мере их появления.
-
После деплоя Kubeflow выполняем вход по адресу (вместо переменных подставьте свои значения):
kubeflow.apps.k8s-$clustername-$env.company.io/ruи авторизуемся с профилем по умолчанию —
user@example.comи паролем12341234. -
Первоначальная установка Kubeflow завершена.
А что дальше?
Изначально в банке использовались две системы, которые не могли корректно работать вместе. Мы задеплоили их в два разных кластера, которые синхронно управляются платформой «Штурвал» — и благодаря этому они больше не конфликтуют.
В результате мы получили управляемую, безопасную и надежную ML-платформу. Теперь бизнес-заказчики могут быстро разворачивать модели для тестирования своих идей, а инженеры — заказывать и получать необходимые ресурсы.
Гибкое управление видеокартами, включая их разбиение, позволило равномерно использовать GPU-ресурсы. Сейчас они используются оптимально и могут быть при необходимости переконфигурированы. Решение успешно работает на отечественном софте в закрытом окружении.
В планах — автоматизировать процесс подготовки новых worker-нод для ML-платформы. Также мы хотим реализовать управление MIG’ами через подход «Инфраструктура как код». А команда «Штурвала» добавит больше «автоматики» в ближайших релизах 2.13 и 2.14.
Что вы думаете об этом опыте? Какие сложности вы видите при построении ML-платформ на Kubernetes? Какие вопросы остались без ответа в статье? Поделитесь своим мнением и задавайте вопросы в комментариях!
Автор: SovcomTech
- Запись добавлена: 12.02.2026 в 14:59
- Оставлено в
Советуем прочесть:
- Как превратить хаотичный ML-проект в систему: пошаговый гайд по DVC + GitHub Actions
- Google DeepMind выпустила полный гайд по Gemini 3
- Google выпустил гайд по созданию работающих AI-агентов
- Практический гайд по использованию Claude Code для код-ревью
- Что нового в Selectel появилось в августе: аддоны в Managed Kubernetes и новые конфигурации
- Как Kubernetes стал стандартом управления инфраструктурой
- Классификация документов: гайд для обхода граблей
- Тренды DevOps 2025: Новые версии K8s и OpenSearch. Гид по главным изменениям
- Axiom Space и Red Hat в 2025 году отправят на МКС компактный дата-центр AxDCU-1
- Kubernetes 1.29 → 1.33 за 30 минут: реальный апгрейд кластера с помощью ИИ под контролем инженера


