在没有“--net 主机"的情况下,在通过 SSH 连接的服务器上可靠地运行 Docker 容器中的 X 应用程序 [英] Run X application in a Docker container reliably on a server connected via SSH without "--net host"

查看:16
本文介绍了在没有“--net 主机"的情况下,在通过 SSH 连接的服务器上可靠地运行 Docker 容器中的 X 应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果没有 Docker 容器,使用 SSH X11 转发 (ssh -X) 在远程服务器上运行 X11 程序非常简单.当应用程序在服务器上的 Docker 容器内运行时,我试图让同样的事情工作.当使用 -X 选项通过 SSH 连接到服务器时,会设置 X11 隧道,并且环境变量$DISPLAY"通常会自动设置为localhost:10.0"或类似的.如果我只是尝试在 Docker 中运行 X 应用程序,则会收到此错误:

Without a Docker container, it is straightforward to run an X11 program on a remote server using the SSH X11 forwarding (ssh -X). I have tried to get the same thing working when the application runs inside a Docker container on a server. When SSH-ing into a server with the -X option, an X11 tunnel is set up and the environment variable "$DISPLAY" is automatically set to typically "localhost:10.0" or similar. If I simply try to run an X application in a Docker, I get this error:

Error: GDK_BACKEND does not match available displays

我的第一个想法是使用-e"选项将 $DISPLAY 实际传递到容器中,如下所示:

My first idea was to actually pass the $DISPLAY into the container with the "-e" option like this:

docker run -ti -e DISPLAY=$DISPLAY name_of_docker_image

这有帮助,但不能解决问题.错误信息更改为:

This helps, but it does not solve the issue. The error message changes to:

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

在网上搜索之后,我发现我可以做一些xauth 魔法来修复身份验证.我添加了以下内容:

After searching the web, I figured out that I could do some xauth magic to fix the authentication. I added the following:

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 host"添加到 docker 命令时才有效:

However, this only works if also add "--net host" to the docker command:

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

这是不可取的,因为它使整个主机网络对容器可见.

This is not desirable since it makes the whole host network visible for the container.

现在缺少什么才能让它在没有--net 主机"的情况下在 docker 中的远程服务器上完全运行?

What is now missing in order to get it fully to run on a remote server in a docker without "--net host"?

推荐答案

我想通了.使用SSH连接电脑,使用X11转发时,X通信不使用/tmp/.X11-unix,不需要$XSOCK相关部分.

I figured it out. When you are connecting to a computer with SSH and using X11 forwarding, /tmp/.X11-unix is not used for the X communication and the part related to $XSOCK is unnecessary.

任何 X 应用程序都使用 $DISPLAY 中的主机名,通常是localhost"并使用 TCP 连接.然后通过隧道返回到 SSH 客户端.当对 Docker 使用--net host"时,localhost"对于 Docker 容器和 Docker 主机将是相同的,因此它会正常工作.

Any X application rather uses the hostname in $DISPLAY, typically "localhost" and connects using TCP. This is then tunneled back to the SSH client. When using "--net host" for the Docker, "localhost" will be the same for the Docker container as for the Docker host, and therefore it will work fine.

当没有指定--net host"时,Docker使用的是默认的bridge网络模式.这意味着localhost"意味着容器内的其他东西而不是主机,容器内的X应用程序将无法通过引用localhost"来看到X服务器.因此,为了解决这个问题,必须将localhost"替换为主机的实际 IP 地址.这通常是172.17.0.1"或类似的.检查docker0"接口的ip addr".

When not specifying "--net host", the Docker is using the default bridge network mode. This means that "localhost" means something else inside the container than for the host, and X applications inside the container will not be able to see the X server by referring to "localhost". So in order to solve this, one would have to replace "localhost" with the actual IP-address of the host. This is usually "172.17.0.1" or similar. Check "ip addr" for the "docker0" interface.

这可以通过 sed 替换来完成:

This can be done with a sed replacement:

DISPLAY=`echo $DISPLAY | sed 's/^[^:]*(.*)/172.17.0.11/'`

此外,SSH 服务器通常未配置为接受到此 X11 隧道的远程连接.然后必须通过编辑 /etc/ssh/sshd_config(至少在 Debian 中)和设置来更改:

Additionally, the SSH server is commonly not configured to accept remote connections to this X11 tunnel. This must then be changed by editing /etc/ssh/sshd_config (at least in Debian) and setting:

X11UseLocalhost no

然后重启SSH服务器,用ssh -X"重新登录服务器.

and then restart the SSH server, and re-login to the server with "ssh -X".

这就差不多了,但还有一个并发症.如果 Docker 主机上正在运行任何防火墙,则必须打开与 X11 隧道关联的 TCP 端口.端口号是 $DISPLAY 中 :. 之间的数字加上 6000.

This is almost it, but there is one complication left. If any firewall is running on the Docker host, the TCP port associated with the X11-tunnel must be opened. The port number is the number between the : and the . in $DISPLAY added to 6000.

要获取 TCP 端口号,您可以运行:

To get the TCP port number, you can run:

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

然后(如果使用 ufw 作为防火墙),为 172.17.0.0 子网中的 Docker 容器打开此端口:

Then (if using ufw as firewall), open up this port for the Docker containers in the 172.17.0.0 subnet:

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

所有的命令都可以放在一个脚本中:

All the commands together can be put into a script:

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.11/'`
sudo docker run -ti --rm -e DISPLAY=$DISPLAY -v $XAUTH:$XAUTH 
   -e XAUTHORITY=$XAUTH name_of_docker_image

假设您不是 root,因此需要使用 sudo.

Assuming you are not root and therefore need to use sudo.

代替 sudo chmod 777 $XAUTH,你可以运行:

sudo chown my_docker_container_user $XAUTH
sudo chmod 600 $XAUTH

防止服务器上的其他用户也能够访问 X 服务器,如果他们知道您为什么创建了/tmp/.docker.auth 文件.

to prevent other users on the server from also being able to access the X server if they know what you have created the /tmp/.docker.auth file for.

我希望这能让它在大多数情况下都能正常工作.

I hope this should make it properly work for most scenarios.

这篇关于在没有“--net 主机"的情况下,在通过 SSH 连接的服务器上可靠地运行 Docker 容器中的 X 应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆