Привет! Меня зовут Александр Подмосковный, я работаю в Московском кредитном банке и, как многие, увлёкся темой искусственного интеллекта. Когда модель DeepSeek R1 стала широко обсуждаться в сообществе, я заинтересовался, можно ли эффективно использовать её и другие крупные модели в домашних условиях, не прибегая к дорогостоящим облачным сервисам. Так как DevOps и инфраструктурой я увлекаюсь уже несколько лет, за это время у меня постепенно сформировалась домашняя лаборатория, на которой я и решил проверить эту идею.
Одним из результатов воплощения идеи в жизнь стала эта статья. Это пошаговая инструкция реализации распределённого инференса с использованием Ray Serve, vLLM, Kubernetes, Proxmox и других технологий. Для удобства чтения я разделил статью на три части, все они будут опубликованы на этой неделе.
В этой, первой, части мы настроим GPU и проброс в Proxmox, развернём Kubernetes-кластер, установим GPU Operator и KubeRay Operator. Во второй — напишем скрипт vLLM для шардирования и распределения вычислений, настроим KubeRay Cluster и запустим инференс. В третьей — организуем авторизацию и интеграцию с OpenWebUI и подведём итоги.
Моя мотивация и цель
После того как я развернул урезанную версию модели на 32 млрд параметров с помощью Ollama, у меня возник вопрос: «А можно ли распределить модель, которая не помещается в видеопамять одной GPU, между несколькими GPU?» Оказалось, что такой подход возможен, и я решил поэкспериментировать, используя домашнее оборудование.
Моя цель — использовать доступные видеокарты для запуска более крупных моделей. Это помогло бы снизить порог вхождения для многих разработчиков и компаний с точки зрения отношения инвестиции/профит. Отсюда родилась идея распределённой архитектуры инференса, включающей шардирование и эффективное использование нескольких видеокарт.
Важно отметить, что описанный мной кластер — результат нескольких лет постепенного развития и вложений. Для повторения решения из статьи в упрощённом виде достаточно пары серверов с доступными GPU, такими как RTX 3090, которые намного дешевле профессиональных аналогов.
Введение в распределённый инференс и шардирование
Проблема работы с большими моделями, которые не помещаются в память одной видеокарты, решается двумя основными подходами:
-
Распределение вычислений между несколькими GPU.
-
Шардирование модели.
Модели с большим числом параметров, например Llama, GPT или DeepSeek, требуют значительных вычислительных ресурсов. Использование нескольких видеокарт для распараллеливания инференса позволяет эффективно обрабатывать запросы без необходимости в супердорогих вычислительных мощностях.
Шардирование модели помогает разделить её на несколько частей (шардов) и загрузить их на разные GPU. Благодаря этому модели, которые не помещаются в память одного устройства, могут работать на нескольких видеокартах одновременно.
В отличие от обычного распределённого инференса, где каждая видеокарта может обрабатывать один запрос, шардирование позволяет видеокартам работать параллельно с разными частями модели, делая инференс быстрее и эффективнее.
Моя домашняя лаборатория
Моя текущая лаборатория — это кластер из 14 серверов. Понимаю, что для большинства задач и проектов такой масштаб не требуется. Это скорее результат длительного увлечения технологиями, чем необходимость для запуска LLM.
Для запуска распределённого инференса и описанных в статье задач вполне хватит небольшого количества узлов и GPU среднего уровня, таких как RTX 3090 с 24 ГБ памяти. На вторичном рынке они доступны за ~70 тысяч рублей.
Вот оборудование, с которым я буду работать:
-
7 серверов для рабочих нагрузок — гиперконвергентные системы на базе материнских плат Supermicro X11 и процессоров Intel Xeon Scalable:
-
Сеть 4 × 10Gbe (LACP) для высокой пропускной способности.
-
Из них 4 сервера с GPU:
-
1 × RTX 3060 (12Gb);
-
3 × RTX 3090 (24Gb).
-
-
NVMe-диски:
-
часть используется для ZFS с RAIDZ02 под БД;
-
часть используется для Ceph (RBD, CephFS, RGW).
-
-
-
7 машин для Control Plane и балансировок:
-
Некоторые на NUC-устройствах, другие — на потребительском железе.
-
Всё это работает в кластере Proxmox 8.4.1 с Ceph 19.2.1, что позволяет мне проводить эксперименты с распределёнными системами.

Для комфортного повторения моих экспериментов вполне достаточно иметь:
-
2–3 сервера или мощных ПК, совместимых с GPU;
-
2–3 видеокарты RTX 3090 (24 ГБ) или хотя бы RTX 3060 (12 ГБ);
-
простое сетевое оборудование (1GbE или 10GbE по возможности).
Как устроен мой кластер
Для реализации распределённого инференса и шардирования модели я выбрал Ray Serve и vLLM за их простоту настройки, хорошую документацию и сообщество. Такая архитектура позволяет распределять как данные, так и вычисления между несколькими GPU. Это обеспечивает масштабируемость и высокую производительность. Существуют и альтернативные решения, например NVIDIA Triton или TorchServe, но они требуют большей подготовки и сложнее в домашнем развёртывании.
Основные компоненты:
-
Kubernetes-кластер, развёрнутый с помощью Deckhouse. Он позволяет динамически добавлять узлы с GPU и масштабировать вычисления. Этот кластер — основа для всех вычислений и развёртывания моделей.
-
Kuberay — оператор для управления кластером Ray, используемый для запуска распределённых задач.
-
Ray Serve — компонент для развёртывания API-интерфейсов, который интегрируется с vLLM для обработки запросов.
-
vLLM — библиотека для эффективного распределения инференса на несколько GPU с использованием NVIDIA Collective Communications Library (NCCL), которая управляет шардированием и синхронизацией данных между видеокартами.
Всё это работает следующим образом:
-
Модели загружаются и разбиваются на части. Каждая часть модели загружается на отдельную видеокарту.
-
Ray Serve обрабатывает входящие HTTP-запросы, направляя их к vLLM, которая управляет распределением данных и вычислений.
-
vLLM и NCCL синхронизируют вычисления между GPU, что позволяет эффективно использовать всю доступную вычислительную мощность.
-
OpenAI API-совместимый эндпойнт настроен через FastAPI, чтобы интегрироваться с другими инструментами и сервисами.

Преимущества такой архитектуры и вызовы
Преимущества:
-
Масштабируемость: можно увеличивать вычислительные ресурсы, добавляя новые GPU.
-
Экономия: RTX 3090 была выбрана за оптимальное соотношение памяти (24 ГБ) и стоимости на вторичном рынке. Это позволяет экономично использовать несколько GPU вместо одной дорогой серверной карты, например NVIDIA A100.
-
Гибкость: архитектура легко адаптируется под разные задачи и модели.
Вызовы:
-
Управление нагрузкой: необходимо эффективно управлять распределением данных и вычислений между GPU, чтобы избежать узких мест в производительности.
-
Сложность настройки: настройка распределённого инференса требует внимательности к деталям, например правильного использования vLLM для синхронизации данных между устройствами.
Как это работает на практике
В трёх частях статьи я расскажу, как и вам настроить и развернуть это решение. Мы разберём:
-
Настройку Kubernetes — как настроить Kubernetes, добавить узлы с GPU, настроить Proxmox и подключиться к кластеру Ceph — и Ray для распределённого инференса.
-
Настройку vLLM для шардирования модели и распределения вычислений между несколькими GPU.
-
Конфигурацию Ray Serve для обработки запросов через FastAPI.
-
Примеры запросов и то, как интегрировать систему с существующими решениями.
Настройка GPU и проброс в Proxmox
В этом разделе мы подготовим виртуальные машины для будущего Kubernetes-кластера и обеспечим прямой доступ к видеокартам через технологию PCI passthrough в среде Proxmox. Такой подход позволяет эффективно задействовать ресурсы GPU в виртуализации, избегая потерь производительности и накладных расходов на виртуализацию устройств.
Отмечу, что использование Proxmox и PCI passthrough — это всего лишь один из возможных способов реализации подобного решения. Например, аналогичные задачи можно решать с помощью прямого использования физических серверов без виртуализации (bare-metal), применения других гипервизоров (например, VMware ESXi, KVM/QEMU без Proxmox) или же контейнеризации с прямым доступом к устройствам через Docker или Podman.
Выбор Proxmox в моём случае был обусловлен удобством управления, открытым исходным кодом и простотой реализации проброса GPU, что отлично подходит для экспериментов и домашних лабораторий. Однако вы можете адаптировать описанный ниже подход и под другие технологии в зависимости от ваших предпочтений и опыта.
Частые ошибки:
-
Убедитесь, что IOMMU и PCI passthrough корректно включены в BIOS.
-
Не забудьте поместить стандартные видеодрайверы (nouveau, nvidia) в blacklist, иначе GPU не пробросится.
Настройка GRUB
Для включения IOMMU и корректного проброса PCI-E-устройств отредактируйте загрузчик GRUB:
1. Откройте файл /etc/default/grub
.
2. В строке GRUB_CMDLINE_LINUX_DEFAULT
добавьте параметры (в примере для процессоров Intel):
intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction
Пример:
GRUB_CMDLINE_LINUX_DEFAULT="quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction"
3. Сохраните изменения и обновите загрузчик:
update-grub
Поиск и проверка GPU
Дальше просмотрите все PCI-устройства:
lspci
Найдите нужную видеокарту, например по адресу 65:00
, и определите её идентификаторы:
lspci -n -s 65:00
Вывод в моём случае:
65:00.0 0300: 10de:2203 (rev a1)
65:00.1 0403: 10de:1aef (rev a1)
Блокировка конфликтующих драйверов
Чтобы стандартные драйверы не перехватывали управление GPU, внесите их в «чёрный список»:
-
Откройте
/etc/modprobe.d/blacklist.conf
. -
Добавьте строки:
blacklist radeon
blacklist nouveau
blacklist nvidia
blacklist nvidiafb
Загрузка необходимых модулей
Укажите модули ядра, требуемые для VFIO, в файле /etc/modules
:
vfio
vfio_iommu_type1
vfio_pci
vfio_virqfd
Настройка VFIO
Создайте или отредактируйте /etc/modprobe.d/vfio.conf
.
Добавьте строку с идентификаторами ваших устройств из шага «Поиск и проверка GPU»:
options vfio-pci ids=10de:2203,10de:1aef
Обновление initramfs
Примените изменения, обновив initramfs
:
update-initramfs -u -k all
Перезагрузка сервера
Перезагрузите систему, чтобы применить новые настройки:
reboot
Маппинг GPU в интерфейсе Proxmox
В веб-интерфейсе Proxmox перейдите в Datacenter
→ Resource Mapping
. Найдите нужное PCI-E-устройство (GPU) и выполните маппинг согласно подсказкам в интерфейсе.

Добавление GPU к виртуальной машине
В настройках виртуальной машины откройте раздел Hardware
. Выберите Add
→ PCI Device
и укажите свою видеокарту, которую вы ранее замапили.

Промежуточные итоги
Теперь у нас:
-
Proxmox настроен на проброс GPU в виртуальные машины (PCI passthrough).
-
Виртуальные машины могут использовать мощность видеокарт напрямую.
-
Выполнены базовые условия для дальнейшего развёртывания распределённого инференса с Ray Serve, vLLM и так далее.
Настройка Kubernetes, добавление GPU-узлов, установка GPU Operator и KubeRay Operator
В этом разделе мы установим Kubernetes-кластер с помощью Deckhouse и настроим узлы с поддержкой GPU. Здесь же даны YAML-файлы конфигурации — config.yml и resources.yml — и подробные комментарии к ним.
Подготовка узлов для Kubernetes с Deckhouse
Для развёртывания Kubernetes-кластера внутри виртуальных машин рекомендую использовать образ Ubuntu 22.04 — он стабилен и обладает хорошей поддержкой современных драйверов и компонентов Kubernetes.
Я использую Deckhouse Kubernetes Platform Enterprise Edition — «Флант» любезно предоставил триальную лицензию для исследования функционала платформы. Однако описанные ниже возможности, включая интеграцию и работу узлов с GPU, полностью доступны и в бесплатной редакции Community Edition.
Для развёртывания кластера с Deckhouse Kubernetes Platform вы можете следовать официальной документации. Там подробно описан процесс установки и настройки, включая интеграцию узлов с GPU.
Краткий обзор процесса установки
-
Вы логинитесь в приватный Docker Registry Deckhouse, используя предоставленный лицензионный ключ (для EE-версии).
-
Запускаете контейнер Deckhouse Installer, где выполняется команда
dhctl bootstrap
. -
По завершении развёртывания у вас будет готовый Kubernetes-кластер, который можно масштабировать и дополнять.
-
После успешного запуска кластера устанавливаете и настраиваете KubeRay поверх Kubernetes, что позволит управлять ресурсами GPU в рамках Ray.
Пример запуска
Шаг 1. Аутентификация и запуск контейнера:
base64 -d <<< <LicenseKey> | docker login -u license-token --password-stdin registry.deckhouse.ru
docker run --pull=always -it
-v "$PWD/config.yml:/config.yml"
-v "$HOME/.ssh/:/tmp/.ssh/"
-v "$PWD/resources.yml:/resources.yml"
-v "$PWD/dhctl-tmp:/tmp/dhctl"
--network=host
registry.deckhouse.ru/deckhouse/ee/install:stable bash
Шаг 2. Запускаем установку внутри контейнера:
dhctl bootstrap --ssh-user=root --ssh-host=192.168.3.51 --ssh-agent-private-keys=/tmp/.ssh/id_ed25519
--config=/config.yml
--config=/resources.yml
--ask-become-pass
Файлы конфигурации
Когда я начал развёртывать домашний Kubernetes-кластер, то использовал официальный быстрый старт от Deckhouse, в котором есть только один конфигурационный файл — config.yml
. Второй файл — resources.yml
— я составлял самостоятельно, руководствуясь документацией Deckhouse Kubernetes Platform и конкретными требованиями своего домашнего кластера. Это позволило мне сразу после первой установки получить полностью готовую рабочую среду без ручной донастройки.
Первый файл — config.yml.
Большинство настроек этого файла я взял из официальной документации Deckhouse и не менял, так как они хорошо подходили для моего случая:
-
Версия Kubernetes — 1.30. Выбрал стабильную версию 1.30 для совместимости с текущей версией KubeRay и vLLM.
-
Подсети. Подсети для подов (
10.111.0.0/16
) и сервисов (10.222.0.0/16
) — стандартные из примера Deckhouse. А вот дляinternalNetworkCIDRs
я взял свою домашнюю подсеть (192.168.2.0/23
) — ноды размещены именно в ней. -
releaseChannel и bundle. Использую канал обновлений Stable и стандартный набор модулей (Default bundle), чтобы избежать неожиданных изменений и иметь проверенные обновления платформы.
-
customTolerationKeys (
- dedicated.example.com
) необходимо указывать, чтобы позволить планировщику размещать критически важные компоненты Deckhouse Kubernetes Platform на выделенных узлах. -
ingressClass: system-ingress
— задал класс ingress по умолчанию.
Модули Deckhouse Kubernetes Platform. Сразу активировал те модули, которые были мне критично важны:
-
csi-ceph — моё основное хранилище данных на домашнем Ceph-кластере (также указал
defaultClusterStorageClass: "ceph-rbd-sc"
). -
cert-manager — автоматическое получение внутренних сертификатов через мой промежуточный (intermediate) CA. Чтобы всё работало, я указал имя cluster issuer в
clusterIssuerName: inter-ca
. -
cni-cilium — включен по умолчанию.
-
metallb и ingress-nginx — обеспечил возможность внешнего доступа к сервисам и балансировки трафика внутри моей сети.
Также включил дополнительные модули безопасности и управления (operator-trivy
, runtime-audit-engine
, multitenancy-manager
, console
).
Второй файл — resources.yml.
Этот файл я собирал самостоятельно, чтобы сразу получить необходимые мне дополнительные настройки и интеграции:
-
Ceph-хранилище. Указал IP-адреса своих Ceph-мониторов (
192.168.3.10
,.11
,.12
) и ключ доступа пользователя, чтобы Deckhouse автоматически создал StorageClass (RBD и CephFS) без дополнительной конфигурации. -
Группы узлов (NodeGroup). Чётко разделил роли узлов и настроил метки и taints, чтобы контролировать размещение подов Kubernetes:
-
w-gpu (RTX 3090) и w-gpu-3060 — с taints
dedicated.example.com=w-gpu:NoExecute
, чтобы GPU-узлы были выделены строго под задачи машинного обучения и инференса. -
w-std — 6 стандартных рабочих узлов под общие задачи.
-
w-db — с taints
dedicated.example.com=w-db:NoExecute
, чтобы выделить 3 узла под базы данных.
-
-
LocalPathProvisioner. Для нод w-db — точечно настроил локальное хранилище на NVMe-дисках, где держу ZFS-RAIDZ02.
-
NodeGroupConfiguration — скрипты для автоматической настройки узлов. Уникальная возможность Deckhouse, которой нет в ванильном Kubernetes:
-
install-cuda.sh
— устанавливает CUDA и nvidia-container-toolkit, без чего GPU не заработали бы полноценно. -
containerd-additional-config.sh
— включает поддержку GPU-контейнеров в containerd (nvidia-container-runtime). -
add-gitlab-registry-cert.sh
— для экспериментов у меня есть внутренний GitLab registry, буду его использовать для собственных Docker-образов, поэтому добавляю его в настройки containerd.
-
Эти скрипты полностью автоматизируют подготовку моих узлов без необходимости использования внешних плейбуков Ansible.
-
StaticInstance. Список статических узлов с IP-адресами для автоматического подключения Deckhouse через SSH.
-
IngressNginxController и MetalLB. Создал два Ingress-контроллера (public и internal), настроив MetalLB на автоматическое выделение внешних IP из указанного мной адресного пула.
-
Пользователи и авторизация (ClusterAuthorizationRule и User). Создал одного администратора (
admin
) с полными правами, чтобы максимально упростить работу с кластером. -
TLS и сертификаты. Настроил внутренний CA (intermediate CA), создав Secret (
internal-ca-key-pair
) и ClusterIssuer (inter-ca
). Это решение дало мне полный контроль над внутренними сертификатами и существенно упростило управление безопасностью. По умолчанию приложения во внутренней сети уже доверяли этому CA.
Структура кластера после установки
-
3 мастер-узла;
-
6 worker-узлов (w-std);
-
3 worker-узла для баз данных (w-db);
-
4 GPU-узла (w-gpu, w-gpu-3060).

Установка и настройка KubeRay поверх Kubernetes
После успешного развёртывания Deckhouse-кластера можно добавить KubeRay. Есть два варианта:
-
При желании установить Argo CD, чтобы управлять манифестами и Helm-чартами через GitOps.
-
Использовать Helm напрямую для установки нужных компонентов.
Установка GPU Operator
NVIDIA GPU Operator упрощает и автоматизирует процесс установки и обновления драйверов, утилит и сервисов для GPU на узлах Kubernetes. Он проверяет, на каких узлах есть GPU, и развёртывает на них:
-
NVIDIA-драйвер, который может собирать динамически или использовать готовые образы при наличии поддержки в вашей ОС;
-
nvidia-container-runtime, чтобы поды, запущенные на GPU-узлах, могли видеть устройства GPU и использовать их;
-
DCGM (Data Center GPU Manager) и DCGM Exporter для метрик и мониторинга;
-
MIG Manager при необходимости, если вы используете разбивку GPU (Multi-Instance GPU), которая доступна только на некоторых профессиональных картах.
Обратите внимание, что для домашнего кластера удобнее использовать готовые образы от NVIDIA, чтобы не собирать драйверы вручную.
Как это работает
-
Operator реагирует на появление или изменение узлов с лейблами вида
nvidia.com/gpu.deploy.operands=true
или аналогичной логики и устанавливает на них драйверы и сервисы. -
Каждый узел получает DaemonSet от GPU Operator, который развёртывает нужные компоненты.
-
Управление драйверами: обновления, перезагрузка при новых версиях, мониторинг статуса (через DCGM).
Файл ap-values.yaml
В файле ap-values.yaml для GPU Operator задаются:
-
путь к репозиторию NVIDIA — registry, теги образов;
-
включение/выключение Node Feature Discovery (NFD) — автоматически определяет тип GPU и добавляет лейблы;
-
детальная настройка daemonsets, updateStrategy, tolerations, при желании – driver (версия, precompiled-драйверы, запуск autoUpgrade);
-
включение отдельных компонентов (MIG, DCGM, DCGM Exporter, GDS, vGPU, VFIO и прочих).
Ключевые поля:
-
driver.enabled: true/false
— указывает, нужно ли устанавливать драйвер напрямую; -
mig.strategy: single
— обозначает, используете ли вы MIG в полном объёме, частично или вовсе нет; -
devicePlugin.enabled: true
— активирует установку Device Plugin, чтобы Kubernetes мог корректно назначать GPU-поды на узлы; -
dcgm.enabled: true / dcgmExporter.enabled: true
— управляют сбором метрик GPU.
Установка KubeRay Operator
KubeRay Operator — это оператор для Kubernetes, который позволяет:
-
создавать, управлять и масштабировать Ray-кластеры (RayCluster CRD);
-
запускать задачи и сервисы в виде RayJob, RayService и так далее;
-
автоматически распределять нагрузку по доступным узлам, включая GPU-узлы.
Как это работает
-
KubeRay Operator устанавливает Custom Resource Definitions (CRDs), такие как
RayCluster
,RayJob
,RayService
. -
Когда в кластере появляется ресурс типа
RayCluster
, оператор создаёт нужное количество подов Ray (Head, Worker) и управляет их жизненным циклом (автоматический рестарт, масштабирование, обновления). -
Для работы с GPU Operator KubeRay Operator использует нативные механизмы Kubernetes (labels, taints, Device Plugin и прочие), чтобы запускать RayWorker’ы на узлах, где есть доступные GPU.
Файл ap-values.yaml
В конфигурационном файле ap-values.yaml для KubeRay Operator можно указать:
-
образ оператора (репозиторий, теги);
-
параметры Pod Security (
securityContext
,podSecurityContext
), если важен комплаенс; -
RBAC (роль, которую получит оператор), в том числе для leader election и управления ресурсами в своих пространствах имён;
-
watchNamespace
— список пространств имён, в которых оператор будет слушать события CRD (можно ограничиться одним пространством имён); -
batchScheduler
— если хотите интеграцию с кастомными планировщиками (Volcano, YuniKorn); -
env-переменные (например,
ENABLE_INIT_CONTAINER_INJECTION=true
), управляющие поведением Ray-подов.
Пример с подробными комментариями приведён в блоке values.yaml. Ключевые моменты:
-
image.repository
иimage.tag
— где хранится оператор; -
resources
— рекомендуемые ресурсы для пода оператора (CPU, RAM); -
leaderElectionEnabled
— нужен, если вы хотите запускать несколько реплик оператора для отказоустойчивости; -
singleNamespaceInstall
— при значенииtrue
оператор будет работать только в одном пространстве имён и вы не сможете управлять Ray-кластерами за его пределами.
Промежуточные итоги
Итак, теперь у нас:
-
Настроена Deckhouse Kubernetes Platform для управления кластером (Ceph, Ingress, Cilium, MetalLB и так далее).
-
Настроены узлы с GPU (CUDA, nvidia-container-runtime), что даёт возможность запускать высоконагруженные задачи.
-
Установлен GPU Operator (от NVIDIA) для автоматического управления драйверами, мониторингом и ресурсами GPU.
-
Установлен KubeRay Operator, который позволяет развёртывать Ray-кластеры и использовать ресурсы GPU непосредственно внутри Kubernetes.
В следующей части
В следующей статье мы рассмотрим, как организовать распределённый инференс с помощью vLLM и обеспечить доступ к нему через Ray Serve, а также разберёмся, как подготовить Docker-образ, поместить его в Registry и развернуть Ray Cluster с нужными параметрами.
Минутка рекламы
20 мая в 19:35 я выступаю на первом митапе Deckhouse User Community с докладом по теме этой статьи. Если вам комфортнее слушать, а не читать, регистрируйтесь и подключайтесь. Места в Москве закончились, но можно присоединиться онлайн.
Автор: Myskat_90