Запустите приложение X в контейнере Docker надежно на сервере, подключенном через SSH, без хоста --net

Без контейнера Docker прямое выполнение программы X11 на удаленном сервере с использованием пересылки SSH X11 (ssh -X). Я попытался заставить ту же самую работу работать, когда приложение запускается внутри контейнера Docker на сервере. При SSH-входе на сервер с параметром -X туннель X11 настраивается, а переменная среды "$ DISPLAY" автоматически устанавливается как обычно "localhost: 10.0" или аналогичная. Если я просто попробую запустить X-приложение в Docker, я получаю эту ошибку:

Error: GDK_BACKEND does not match available displays

Моя первая идея состояла в том, чтобы фактически передать $ DISPLAY в контейнер с параметром "-e" следующим образом:

docker run -ti -e DISPLAY=$DISPLAY name_of_docker_image

Это помогает, но это не решает проблему. Сообщение об ошибке изменится на:

Unable to init server: Broadway display type not supported: localhost:10.0
Error: cannot open display: localhost:10.0

После поиска в Интернете я понял, что могу исправить магию xauth, чтобы исправить аутентификацию. Я добавил следующее:

SOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
chmod 777 $XAUTH
docker run -ti -e DISPLAY=$DISPLAY -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH \ 
  -e XAUTHORITY=$XAUTH name_of_docker_image

Однако это работает только в том случае, если также добавить " --net хост " в команду докера:

docker run -ti -e DISPLAY=$DISPLAY -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH \ 
  -e XAUTHORITY=$XAUTH --net host name_of_docker_image

Это нежелательно, так как делает всю сеть хоста видимой для контейнера.

Что теперь отсутствует, чтобы полностью запустить его на удаленном сервере в докере без "--net хоста"?

Ответ 1

Я понял. Когда вы подключаетесь к компьютеру с SSH и используете пересылку X11, /tmp/.X11-unix не используется для связи X, и часть, связанная с $ XSOCK, не нужна.

Любое приложение X скорее использует имя хоста в $ DISPLAY, обычно "localhost", и подключается с использованием TCP. Это тогда передано обратно клиенту SSH. При использовании "--net host" для Docker "localhost" будет таким же для контейнера Docker, как и для хоста Docker, и поэтому он будет работать нормально.

Если не указано "--net host", Docker использует режим мостовой сети по умолчанию. Это означает, что "localhost" означает что-то другое внутри контейнера, чем для хоста, и X-приложения внутри контейнера не смогут видеть X-сервер, ссылаясь на "localhost". Таким образом, чтобы решить эту проблему, нужно заменить "localhost" фактическим IP-адресом хоста. Обычно это "172.17.0.1" или подобное. Проверьте "ip addr" на наличие интерфейса "docker0".

Это можно сделать с помощью замены sed:

DISPLAY='echo $DISPLAY | sed 's/^[^:]*\(.*\)/172.17.0.1\1/''

Кроме того, сервер SSH обычно не настроен для приема удаленных подключений к этому туннелю X11. Затем это необходимо изменить, отредактировав /etc/ssh/sshd_config (по крайней мере, в Debian) и установив:

X11UseLocalhost no

а затем перезапустите сервер SSH и повторно войдите на сервер с помощью "ssh -X".

Это почти все, но осталось одно осложнение. Если на хосте Docker работает какой-либо брандмауэр, должен быть открыт TCP-порт, связанный с туннелем X11. Номер порта - это число между : и . в $ DISPLAY, добавленное к 6000.

Чтобы получить номер порта TCP, вы можете запустить:

X11PORT='echo $DISPLAY | sed 's/^[^:]*:\([^\.]\+\).*/\1/''
TCPPORT='expr 6000 + $X11PORT'

Затем (при использовании ufw в качестве брандмауэра) откройте этот порт для контейнеров Docker в подсети 172.17.0.0:

ufw allow from 172.17.0.0/16 to any port $TCPPORT proto tcp

Все команды вместе можно поместить в скрипт:

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | sudo xauth -f $XAUTH nmerge -
sudo chmod 777 $XAUTH
X11PORT='echo $DISPLAY | sed 's/^[^:]*:\([^\.]\+\).*/\1/''
TCPPORT='expr 6000 + $X11PORT'
sudo ufw allow from 172.17.0.0/16 to any port $TCPPORT proto tcp 
DISPLAY='echo $DISPLAY | sed 's/^[^:]*\(.*\)/172.17.0.1\1/''
sudo docker run -ti --rm -e DISPLAY=$DISPLAY -v $XAUTH:$XAUTH \
   -e XAUTHORITY=$XAUTH name_of_docker_image

Если вы не являетесь пользователем root и, следовательно, должны использовать sudo.

Вместо sudo chmod 777 $XAUTH вы можете запустить:

sudo chown my_docker_container_user $XAUTH
sudo chmod 600 $XAUTH

чтобы другие пользователи на сервере также не могли получить доступ к X-серверу, если они знают, для чего вы создали файл /tmp/.docker.auth.

Я надеюсь, что это должно сделать это правильно для большинства сценариев.

Ответ 2

Следуя вашим шагам, я все равно получаю следующую ошибку: "Соединение X11 отклонено из-за неправильной проверки подлинности. Ошибка: не удается открыть дисплей: 172.17.0.1:10.0