
В Яндексе постоянно растёт количество задач, где GPU требуются не только для классического машинного обучения, но и для генерации тяжёлого визуального контента: 3D‑сцен, видео, цифровых аватаров, симуляций и синтетических данных для обучения нейросетей.
Ярким кейсом стал проект к премьере сериала «Кибердеревня». Мы сканировали гостей мероприятия, создавали их 3DGS‑аватары (3D Gaussian Splatting) и интегрировали в подготовленные Unity‑сцены. Этот пайплайн наглядно подсветил узкое место: при масштабировании производства скорость упирается не в креатив или алгоритмы реконструкции, а в возможности инфраструктуры рендеринга. Стало очевидно, что нам нужно решение, способное ускорить обработку в десятки раз.
Традиционно такие задачи решаются на локальных рабочих станциях или через специализированные внешние рендер‑фермы. Однако в Яндексе уже есть YTsaurus — распределённая система с GPU‑кластерами, поддержкой контейнеризации и отработанными механизмами планирования задач. Меня зовут Анатолий Томилов, я разработчик инфраструктуры VR и 3D‑реконструкции в Фантехе. В статье я расскажу, почему идея использовать YTsaurus в качестве внутренней рендер‑фермы выглядела логичной, но её реализация оказалась нетривиальной.
Проблема графического стека
Для запуска графических приложений недостаточно просто пробросить GPU в контейнер. Таким инструментам, как Unity, Unreal Engine (UE), Blender или кастомным Vulkan/OpenGL‑рендерерам, требуется полноценное окружение:
актуальные драйверы GPU;
поддержка API Vulkan и OpenGL;
X11-сервер и виртуальный дисплей;
доступ к специфическим системным устройствам Linux.
Команда инфраструктуры 3D‑реконструкций прошла путь от базовых тестов до стабильного запуска Unity‑приложения с отрисовкой 3DGS‑аватаров и захватом видеопотока внутри инфраструктуры YTsaurus.
Наша команда работает с MVS/SfM‑пайплайнами, превращая обычные фотографии и видео в текстурированные меши или 3DGS‑сцены (3D Gaussian Splatting). Внутри этого процесса живёт стандартный стек для ML и компьютерного зрения: PyTorch, nvdiffrast, COLMAP и другие инструменты.
Главный инфраструктурный вызов возник на этапе генерации контента. В течение двух дней работы стенда требовалось развернуть пайплайн массового промышленного рендеринга: динамически подставлять кастомные 3D‑аватары отсканированных гостей в готовые Unity‑сцены. Поскольку поток шёл на сотни уникальных объектов, а под каждый ролик требовался свой инстанс сцены, ручные методы и простые скрипты автоматизации исключались. Задача требовала построения отказоустойчивого конвейера с высокой пропускной способностью.
Почему нам не подошли классические виртуальные машины
Рендеринг сцен с высокодетализированными 3DGS‑аватарами и тяжёлыми VFX‑эффектами критичен к объёму VRAM и требует серьёзных вычислительных мощностей. В качестве инфраструктуры мы собирались использовать GPU‑кластер A100 внутри платформы YTsaurus, где видеокарты напрямую пробрасываются в контейнеры с изолированными джобами.
Вариант с развёртыванием классических виртуальных машин с аналогичными GPU отпал из‑за долгого цикла согласования и выделения ресурсов. Попытка заказать годовую квоту под разовую задачу также была нецелесообразной: это затянуло бы сроки и не имело бы экономического обоснования.
Выбор в пользу YTsaurus вместо стандартных виртуальных машин был продиктован характером нагрузки:
Задачи на рендер возникают волнообразно. Держать постоянно включёнными мощные GPU‑виртуалки — значит обречь их на низкую утилизацию в периоды простоя.
В YTsaurus у нас уже были выделенные ресурсы GPU A100 80G. Использование готовой инфраструктуры позволило сразу перейти к экспериментам с распределённой обработкой, не тратя время на развёртывание и конфигурирование парка отдельных серверов.
Пайплайн 3D reconstruction & ML уже находился в YTsaurus, и казалось привлекательным добавить рендеринг получаемой 3D‑реконструкции как ещё один шаг, в конец пайплайна.
Однако наличие GPU в контейнере — это только половина дела. Настоящие сложности начались при попытке запустить в этом окружении графический движок, изначально предназначенный для десктопных ОС.
Технические требования: почему нельзя просто запустить бинарник
У нас уже был опыт рендеринга VR‑контента в YTsaurus через кастомный offscreen‑рендерер на Vulkan. Но новая задача потребовала запуска полноценных движков (Unity/UE), а это добавило в уравнение критическое звено — X11. Чтобы запустить такое приложение в YTsaurus, нужно одновременно обеспечить три условия: GPU‑ускорение, API Vulkan и живой X‑сервер.
Вот почему это превратилось в проблему:
GPU‑ускорение. Без него скорость рендеринга падает до неприемлемой, а программные (software) реализации графических API просто не поддерживают расширения, необходимые современным движкам.
Vulkan. Это основной графический API для движков на Linux, позволяющий выжать максимум из железа.
X11. И здесь кроется главная сложность. Unity и Unreal Engine используют слой Window System Integration (WSI). Даже если нам не нужно физическое окно, библиотеки
XCB/Xlibтребуют его наличия для создания поверхностей (VkSurfaceKHR) иswapchain images, в которые записывается финальный результат рендеринга.
Под капотом рендерера
Процесс аллокации памяти в этой связке выглядит как сложный многослойный пирог. Vulkan ICD (libvulkan_nvidia.so) обращается к /dev/dri/renderD128 для аллокации буферов через DRM render node и к /dev/nvidia0 для выделения видеопамяти напрямую на GPU.
Движок рендерит кадр в эти буферы и передаёт их через протокол DRI3 в виде файловых дескрипторов dma‑buf в X‑сервер (Xorg). Чтобы всё это заработало, Xorg должен:
Быть запущен с использованием DDX (userspace‑драйвер
nvidia_drv.so).Работать именно на том GPU, где движок запрашивал память для swapchain images.
Только при соблюдении этих условий драйвер nvidia_drv.so может импортировать dma-buf из видеопамяти и вывести их на виртуальный монитор. Внутри системы это выглядит как цепочка вызовов: nvidia_drv.so → ioctl на /dev/nvidia-modeset → модуль ядра nvidia-modeset.ko → nvidia-drm.ko, который и регистрирует устройство /dev/dri/card0.
В поисках минимального сетапа
Как мы выяснили, для полноценной работы связки Vulkan + X11 на A100 недостаточно стандартных устройств, которые прокидываются в обычный вычислительный контейнер.
Обычно в распоряжении операции есть:
/dev/nvidiactl— менеджмент ресурсов и межпроцессное взаимодействие;/dev/nvidia0,/dev/nvidia1...— создание логических устройств (VkDevice), отправка команд и синхронизация;/dev/nvidia-uvm— UVM, инициализация драйвера.
Но для графического пайплайна этого мало. Нам критически не хватало:
/dev/nvidia-modeset— управление дисплеем и сигналами вертикальной синхронизации (vblank);/dev/dri/card0— устройство, которое захватывает Xorg, становясь DRM‑мастером;/dev/dri/renderD128— необходимо для аллокацииdma-bufчерез Vulkan ICD.
Чтобы докопаться до истины и запустить Unity‑приложение в облаке, мы пошли от простого к сложному, постепенно сужая круг разрешений.
Шаг 1. Полная свобода в Docker. Сначала мы запустили простейший «кубик» (vkcube из пакета vulkan-tools) на «коммунальной» разработческой виртуалке с A100. На этом этапе мы использовали флаги --gpus all и --privileged. Это позволило подтвердить гипотезу: запустить X11-сервер внутри изолированного контейнера (без проброса сокета с хоста) реально.
Шаг 2. Затягивание гаек. Мы убрали привилегированный режим. Здесь и началось самое интересное: выяснилось, что в контейнер нужно вручную устанавливать драйверные библиотеки, утилиты типа nvidia-smi и DDX‑драйвер, которые раньше подтягивались магией Docker‑рантайма. На этом же этапе мы окончательно сформировали список необходимых /dev/‑устройств.
Шаг 3. Переезд в Porto. Повторили тот же опыт в Porto‑контейнере (нативном для нашей инфраструктуры). Чтобы не собирать образ с нуля, просто экспортировали рабочий Docker‑контейнер в самодостаточный Porto‑слой. Porto требуется, так как позволяет запускать вложенные контейнеры — это когда контейнеры могут запускаться внутри контейнера и получать доступ к подмножеству его ресурсов при той же или большей изоляции, что требуется при развёртывании инфраструктуры YTsaurus.
Шаг 4. «Ванильная» операция в YTsaurus. Попытка запустить тот же vkcube как штатную операцию в YTsaurus. Главный нюанс — управление драйверами. В YTsaurus драйверные библиотеки накладываются автоматически специальным слоем, поэтому их нельзя было оставлять в базовом образе. На этом этапе мы ожидали серию ошибок, которые должны были показать, чего именно не хватает внутри инфраструктуры YTsaurus.
Шаг 5. Финальный босс: Unity + 3DGS. Только после того, как мы научились стабильно крутить «кубик» в YTsaurus, мы перешли к настоящей задаче: запуску Unity‑приложения с аватарами из «Кибердеревни» и рендерингом результата в видеофайл через ffmpeg.
Когда пример был готов, стало ясно: без вмешательства в саму платформу YTsaurus не обойтись. Мы передали кодовую базу коллегам из Yandex Infrastructure, и в рамках тикета по поддержке Xorg для GPU‑хостов необходимые изменения были подготовлены буквально за несколько часов. Спустя пару недель изменения раскатили на ML‑кластер, открыв возможность рендеринга и полноценного графического вывода в операциях YTsaurus для всех пользователей.
Чтобы окончательно убедиться, что мы можем полноценно рендерить действительно продвинутую компьютерную графику, перед запуском нашего приложения я протестировал её на Quake II RTX. Это публичная демка, которая задействует большое количество продвинутых графических технологий. Когда на A100 стабильно запустился Quake, стало понятно: мы можем рендерить массово любой визуальный контент.
Нюансы Unity и ограничения A100
При переходе к финальному шагу — запуску нашего Unity‑приложения — пришлось решить ещё одну специфическую задачу: поднять внутри контейнера шину dbus, без которой движок отказывался инициализироваться.
Также важно понимать специфику работы с серверными картами. Хотя по количеству шейдерных процессоров они находятся где‑то между десктопными RTX 3070 и 3080, их архитектура заточена под другие задачи:
Ray‑Tracing. На A100 физически ноль RT‑ядер. Весь функционал трассировки лучей (который мы видели в Quake II RTX) эмулируется драйвером через Compute‑шейдеры. Это работает быстро только благодаря огромному количеству CUDA‑ядер.
Кодирование видео. У A100 также отсутствуют блоки NVENC (hardware encoding units). Поэтому использовать аппаратное ускорение
ffmpegдля записи результата не получится — приходится полагаться на софтверные кодеки libx264 или libx265. Благо избыточная мощность CPU на GPU‑хостах позволяет делать это без существенных потерь в скорости.
Несмотря на эти архитектурные особенности, огромное количество вычислительных блоков (которых на треть больше, чем во флагманской RTX 3090) делает A100 отличным инструментом для пакетного рендеринга.
Вместо заключения: зачем нам был нужен этот проект
Казалось бы, зачем так заморачиваться с X‑сервером внутри распределённого хранилища? Конечно, для разовых задач всегда проще арендовать мощную виртуалку или собрать ролик на локальной рабочей станции. Но наш кейс с «Кибердеревней» показал, что ручной запуск не подойдёт, если счёт идёт на тысячи однотипных сцен.
Что нам дал этот эксперимент:
Масштабируемость: мы превратили графический рендер в обычную batch‑задачу. Теперь, чтобы развернуть окружение на новой машине, достаточно запустить операцию в YTsaurus.
Утилизация железа: мы научились использовать GPU‑мощности, которые раньше не использовались нами между ML‑задачами, для тяжёлой графики.
Прозрачный пайплайн: графика стала частью общего конвейера обработки данных. Между 3D‑реконструкцией и готовым видеороликом теперь нет ручного звена — всё в рамках одной экосистемы.
На примере этого проекта мы убедились: если приложить немного усилий (и заручиться поддержкой коллег из Yandex Infrastructure), даже сугубо вычислительный кластер можно превратить в мощную графическую рендер‑ферму. Расскажите в комментариях, встречаются ли у вас схожие задачи, где нужно массово рендерить что‑либо за короткий промежуток времени, и как вы их решаете.
