当前位置: 首页 > 面试题库 >

在通过SSH连接的服务器上可靠地在Docker容器中运行X应用程序,而无需使用“ --net host”

轩辕天佑
2023-03-14
问题内容

如果没有Docker容器,则可以使用SSH X11转发( ssh -X
)在远程服务器上直接运行X11程序。当应用程序在服务器上的Docker容器中运行时,我试图使相同的东西正常工作。使用-
X选项通过SSH进入服务器时,将建立X11隧道,并且环境变量“ $ DISPLAY”通常会自动设置为“
localhost:10.0”或类似名称。如果我只是尝试在Docker中运行X应用程序,则会收到此错误:

Error: GDK_BACKEND does not match available displays

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

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

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

这是不理想的,因为它使整个主机网络对于容器可见。

为了使其完全在没有“ –net host”的泊坞窗中的远程服务器上运行,现在缺少什么?


问题答案:

我想到了。当您使用SSH连接到计算机并使用X11转发时,/ tmp / .X11-unix 不用于X通信,并且不需要与$ XSOCK相关的部分。

任何X应用html" target="_blank">程序都使用$ DISPLAY中的主机名(通常为“ localhost”)并使用TCP进行连接。然后将其通过隧道传输回SSH客户端。在将“
–net host”用于Docker时,Docker容器的“ localhost”与Docker主机相同,因此可以正常工作。

如果不指定“ –net host”,则Docker使用默认的网桥网络模式。 这意味着“ localhost”在容器内部的含义不同于主机
,而容器内部的X应用程序将无法通过引用“ localhost”看到X服务器。因此,为了解决此问题,必须用主机的实际IP地址替换“
localhost”。通常为“ 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主机上正在运行任何防火墙,则必须打开与X11隧道关联的TCP端口。端口号是 和之间的数字
在$ DISPLAY中添加到6000。

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

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

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

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

如果他们知道您创建了/tmp/.docker.auth文件的内容,则可以防止服务器上的其他用户也能够访问X服务器。

我希望这会使它在大多数情况下都能正常工作。



 类似资料:
  • 我正在docker容器中运行sql server` 所有这些都成功完成了。现在,当我尝试使用Java连接到数据库时,我得到了错误。 192.168.56.101是我的虚拟机的ip。我正在虚拟机上运行Linux。 我收到通信链路故障错误。 我在谷歌上搜索并找到了一些关于以下链接的解决方案,但没有一个对我有用。 使用JDBC和MySQL解决“通信链路故障” 如何连接docker中作为容器运行的MySQ

  • 问题内容: 我有去grpc服务。我正在开发Mac,塞拉利昂。在本地针对服务运行grpc客户端时,一切都很好,但是在Docker容器中针对相同服务运行相同的客户端时,出现此错误: 这是我的docker文件: 我的命令来建立图像: 我的命令启动Docker容器: 其他资讯: 客户端程序可以在Docker容器中正常运行 连接到常规的休息端点可以正常工作(http2,与grpc相关吗?) 在OS X中运行

  • 我有go grpc服务。我在mac电脑上开发,塞拉。当针对本地服务运行grpc客户机时,一切都很好,但当针对docker容器中的相同服务运行相同客户机时,我会出现以下错误: 下面是我的服务器代码片段:

  • 错误:container_linux.go:247:启动容器进程导致“exec:\”-w\“:在$path中找不到可执行文件”c:\program files\docker toolbox\docker.exe:来自守护进程的错误响应:oci运行时错误:container_linux.go:247:启动容器进程导致“exec:\”-w\“:在$path中找不到可执行文件”。

  • 我希望将状态添加到本地运行的无服务器框架节点应用程序。我遇到了官方的DynamoDb docker映像,我想使用无服务器框架,这个在docker上运行的Dynamodb实例在localhost:8000公开,而不使用sls安装的Dynamodb版本。 我已经尝试将其正常用于nodejs aws sdk,并将endpoint和区域配置为本地。新的用户表已经创建,可以通过aws cli访问数据库——e

  • 其基本思想是运行带有音频和ui的应用程序(vlc、firefox、skype…) 我在使用pulseaudio搜索docker容器,但我找到的所有容器都在TCP上使用pulseaudio流。(应用程序的安全沙箱) https://gist.github.com/hybris42/ce429de428e5af3a344a https://github.com/jlund/docker-chrome-