Удалённый доступ к графике в Linux: от X11 до Docker с GPU

от автора

Привет Хабр! С вами снова ServerFlow, и сегодня мы хотим поговорить об удалённом доступе к графическим приложениям на Linux-серверах. Тема эта стала особенно актуальной в последнее время – всё больше задач требует работы с GPU на удалённых машинах. Будь то рендеринг в Blender на мощном сервере, работа с нейросетями или даже облачный гейминг.

X11 Forwarding: начинаем с простого

В нашей практике мы часто сталкиваемся с ситуациями, когда клиентам нужен доступ к графическому интерфейсу на сервере. Кому-то нужна GPU-ферма для рендеринга 3D графики, другим важно тестировать свои приложения в изолированной среде. А некоторые просто хотят организовать себе удалённое рабочее место с графическим ускорением. Сегодня разберём три популярных способа организации такого доступа – от простого к сложному.

Самый простой способ запустить графическое приложение с сервера – это X11 forwarding через SSH. Для этого даже не нужно ничего дополнительно устанавливать на сервер, достаточно базового пакета openssh.

Подключаемся к серверу командой:

ssh -X -p 47645 serverflow@IP_SSH_Сервера

Флаг -X включает проброс X11. Теперь можно запустить, например, Firefox прямо из консоли:

firefox &
Firefox проброшенный через SSH с открытым Хабром

Firefox проброшенный через SSH с открытым Хабром

На первый взгляд всё работает, но… При запуске браузера сразу становятся заметны подтормаживания интерфейса. Не говоря о том что интерфейс и пользовательский ввод отображаются на экране с очень заметной задержкой измеряемой даже не секундами, а порой минутами. С чем это связано? X11 forwarding работает напрямую с примитивами отрисовки, передавая по сети каждое действие с окном, почти никак не оптимизируя и не сжимая передаваемые данные, которых при передаче видео весьма не мало. На медленном соединении это создаёт заметные задержки.
Даже простая прокрутка веб-страницы генерирует тысячи X11-команд, которые должны быть переданы по сети. А теперь представьте, что происходит при воспроизведении видео или работе с 3D-графикой. Протокол просто не был рассчитан на такие сценарии использования.
Впрочем, винить за это мы X11 не будем, так как создавался он ещё в 1980х, для куда более простых графических интерфейсов, в куда меньших разрешениях и предназначался в основном для академической и корпоративной работы с мэинфреймами.

RDP в Docker: серьёзный подход

Примерная архитектура протокола RDP

Примерная архитектура протокола RDP

Перейдём к более современному решению – RDP-серверу в контейнере Docker с поддержкой GPU. В отличие от X11, протокол RDP изначально проектировался для работы с удалённым рабочим столом через сеть. Он использует умные алгоритмы сжатия, кэширование элементов интерфейса и различные оптимизации специально для графики.

Например, при прокрутке веб-страницы RDP не передаёт каждый кадр целиком. Вместо этого он может передать команду «возьми область экрана X и сдвинь её на Y пикселей вниз», а затем досылает только изменившуюся часть. При воспроизведении видео включаются специальные алгоритмы сжатия, похожие на те, что используются в современных видеокодеках.

Но прежде чем мы запустим наш RDP-сервер, нужно правильно настроить поддержку GPU в Docker. Начнём с установки драйверов и тулкита:

sudo pacman -S nvidia nvidia-container-toolkit

После установки настраиваем Docker для работы с GPU:

sudo nvidia-ctk runtime configure --runtime=docker  sudo systemctl restart docker

Nvidia Container Toolkit добавляет специальный рантайм для Docker, который умеет правильно пробрасывать драйверы и библиотеки CUDA в контейнер. Без этого слоя графическое ускорение работать не будет, так как контейнер по умолчанию изолирован от железа.

Теперь самое интересное – запуск контейнера с RDP-сервером. Мы используем образ от LinuxServer.io с предустановленным XFCE. Создаём директорию для настроек и запускаем:

mkdir -p ~/rdesktop-data  docker run -d \    --name=rdesktop-arch-xfce \    --gpus "device=0" \    --runtime=nvidia \    --security-opt seccomp=unconfined \    -e PUID=1000 \    -e PGID=1000 \    -e TZ=Europe/Moscow \    -p 3389:3389 \    -v ~/rdesktop-data:/config \    --device /dev/dri:/dev/dri \    --shm-size="1gb" \    --restart unless-stopped \    lscr.io/linuxserver/rdesktop:arch-xfce

Разберем каждый параметр, потому что от их правильной настройки зависит стабильность работы нашего удаленного рабочего стола:

Флаг -d запускает контейнер в фоновом режиме. Это значит, что даже если мы закроем терминал, контейнер продолжит работать. Удобно для долгоживущих сервисов вроде нашего RDP-сервера.

—name=rdesktop-arch-xfce даёт контейнеру понятное имя. Потом будет проще найти его в списке контейнеров или перезапустить при необходимости.

Следующие два параметра отвечают за работу с GPU:

  • —gpus «device=0» указывает какую именно видеокарту использовать, если их несколько

  • —runtime=nvidia включает специальный режим работы Docker для поддержки GPU

—security-opt seccomp=unconfined отключает некоторые ограничения безопасности. Обычно Docker сильно ограничивает что может делать приложение в контейнере, но для графического интерфейса и работы с GPU нам нужно больше свободы. Да, это немного снижает безопасность, но без этого параметра наш рабочий стол просто не запустится.

Далее идут переменные окружения:

  • PUID=1000 и PGID=1000 задают ID пользователя и группы внутри контейнера. Важно чтобы они совпадали с вашим пользователем на основной системе, иначе будут проблемы с правами доступа к файлам

  • TZ=Europe/Moscow устанавливает часовой пояс. Не забудьте поменять на свой, если живёте в другом регионе

-p 3389:3389 пробрасывает порт для RDP. Первое число – порт на вашей машине, второе – внутри контейнера. Можно изменить первое число если порт 3389 уже занят.

-v ~/rdesktop-data:/config монтирует директорию с настройками. Все изменения в рабочем столе будут сохраняться на вашем диске и переживут перезапуск контейнера. Очень удобно для бэкапов.

—device /dev/dri:/dev/dri даёт контейнеру прямой доступ к графическому оборудованию для аппаратного ускорения. Без этого параметра графика будет работать только через программный рендеринг.

—shm-size=»1gb» увеличивает размер разделяемой памяти. По умолчанию он всего 64 мегабайта, чего явно мало для современных браузеров и других приложений. Гигабайт обычно хватает с запасом.

—restart unless-stopped говорит Docker’у перезапускать контейнер если он вдруг упадёт или сервер перезагрузится. Единственное исключение – если вы сами остановили контейнер командой stop.

Наконец, lscr.io/linuxserver/rdesktop:arch-xfce указывает какой образ использовать. Мы берём готовый образ от команды LinuxServer.io, который построен на базе Arch Linux и использует лёгкий рабочий стол XFCE.

Клиент для RDP – Remmina

После запуска контейнера нам понадобится RDP-клиент для подключения. В Linux одним из лучших вариантов является Remmina – он поддерживает множество протоколов, включая RDP, и умеет работать через SSH-туннель.

Сначала создаем туннель до нашего сервера:

ssh -L 3389:127.0.0.1:3389 -p 47645 serverflow@IP_SSH_Сервера

Запускаем Remmina и создаём новое подключение. В появившемся окне настройки выставляем следующие параметры:

На вкладке «Basic»:

  • Name: любое удобное название

  • Protocol: RDP

  • Server: localhost:3389

  • Username: abc

  • Password: abc (это стандартные данные для образа, рекомендуем сменить после первого входа)

    Интерфейс Remmina на вкладке Basic

    Интерфейс Remmina на вкладке Basic

Переходим на вкладку «SSH Tunnel» и включаем туннелирование:

  • Enable SSH tunnel: включаем

  • Custom: выбираем этот вариант

  • SSH Server: вводим наш адрес сервера – IP_SSH_Сервера:47645

  • Username: serverflow

  • Authentication: выбираем Password или SSH key, если используете ключи

    Интерфейс Remmina на вкладке SSH Tunnel

    Интерфейс Remmina на вкладке SSH Tunnel

После сохранения профиля можно подключаться. При первом подключении Remmina спросит про сертификат RDP – соглашаемся и сохраняем его. Через несколько секунд мы увидим рабочий стол XFCE.

В чём преимущество такой схемы подключения через SSH туннель? Во-первых, это безопасность – весь RDP трафик шифруется SSH. Во-вторых, нам не нужно открывать порт RDP наружу, что снижает риски взлома. Ну и в-третьих, SSH умеет сжимать трафик, что иногда помогает на медленных каналах связи.

Remmina с запущенным удалённым рабочим столом

Remmina с запущенным удалённым рабочим столом

Теперь проверим работает ли проброс GPU в контейнер, для начала обновим систему через консоль и установим nvtop–

sudo pacman -Syu sudo pacman -S nvtop
Remmina с запущенным в консоли nvtop

Remmina с запущенным в консоли nvtop

И как можно заметить система видит установленную в сервер видеокарту от Nvidia, Tesla P100.
Чтобы точно проверить всё ли работает, воспользуемся простой утилитой для базового бенчмарка — glmark2. Для начала установим её –

sudo pacman -S glmark2

И запустим –

nvidia-smi --query-gpu=utilization.gpu,temperature.gpu,memory.used --format=csv -l 1 & glmark2 && kill $!

Remmina с запущенным в консоли бенчмарком glmark2 и nvtop для мониторинга

Remmina с запущенным в консоли бенчмарком glmark2 и nvtop для мониторинга

Как можно заметить, для рендеринга glmark2 использует видеокарту и нагружает её на ~4-5%.

Подводим итоги

В итоге у нас получился полноценный удаленный рабочий стол с поддержкой GPU, работающий в изолированном контейнере. Производительность на высоте – можно комфортно работать с браузером, запускать требовательные приложения и даже смотреть видео без задержек. Во многом это заслуга RDP протокола, который гораздо эффективнее X11 forwarding в плане передачи графики по сети.

Контейнеризация дает нам гибкость – можно быстро развернуть такой же рабочий стол на другом сервере или сделать бэкап всех настроек. А поддержка GPU открывает интересные возможности, например для рендеринга 3D графики или работы с нейросетями прямо через удалённый доступ.

Конечно, настройка получилась чуть сложнее чем простой проброс X11, зато результат того стоит. К тому же, разобравшись один раз, повторить процесс уже гораздо проще.

В следующей статье мы пойдём дальше и покажем, как на базе этого решения сделать свой домашний игровой стрим-сервис. Окажется, что облачный гейминг в духе GeForce Now – это не сложнее чем VDI по RDP. Нужно будет только добавить поддержку геймпадов и настроить передачу звука. Так что оставайтесь на связи!

А пока делитесь в комментариях – как вы решаете задачу удаленного доступа к графическим приложениям? Может быть есть интересные кейсы использования GPU на удаленных серверах? До встречи в следующей статье!

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

Что используете для VDI?

41.46% VNC17
43.9% RDP18
7.32% Готовое решение в виде сервиса по подписке3
7.32% Другое — Ответ в комментариях3

Проголосовал 41 пользователь. Воздержались 17 пользователей.

ссылка на оригинал статьи https://habr.com/ru/articles/852792/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *