docker 中的 GUI 应用程序的 X11 转发 运行

X11 forwarding of a GUI app running in docker

首先:我已经在 SO 上阅读了类似问题的答案,但是 none 有效。

重要提示:下面的答案仍然有效,但可能会跳到最后寻找替代方案。

情况:

什么有效:

一些设置信息:

什么不起作用:

X11 connection rejected because of wrong authentication.

xterm: Xt error: Can't open display: host-ip-addr:10.0

我尝试过的事情:

我怎样才能禁用所有 X 安全功能并使其正常工作?

甚至更好:我怎样才能让它与安全一起工作?

是否至少有一种方法可以启用广泛的调试以查看问题的确切位置?

备选方案:下面的第一个答案显示了如何有效解决此问题。但是:我建议您一起研究一种不同的方法,即 VNC。我个人切换到替换 X11 转发的 tigerVNC 设置并且没有回头。性能仅高于 X11 转发为我提供的性能。在某些情况下,您可能出于某种原因无法使用 VNC,但我会先尝试一下。

现在的一般设置如下: -VNC 服务器在主机上的机器 A 上运行(不在 docker 容器内)。 -现在您只需要弄清楚如何在 docker 容器内获取 GUI(这是一项微不足道的工作)。 -如果 docker 容器不是从 VNC 环境启动的,DISPLAY 变量可能需要 ajdusting。

好的,事情是这样的:

1) 登录远程机器

2) 检查用 echo $DISPLAY

设置了哪个显示

3) 运行 xauth list

4) 复制与您的 DISPLAY

对应的行

5) 输入您的 docker 容器

6) xauth add <the line you copied>*

7) 使用 export DISPLAY=<ip-to-host>:<no-of-display>

设置显示

*到目前为止一切顺利吧?

这不是什么新鲜事...但是这里有一个转折点: xauth list 为登录用户打印的行看起来像这样(在我的例子中):

<hostname-of-machine>/unix:<no-of-display> MIT-MAGIC-COOKIE-1 <some number here>

因为我使用桥接 docker 设置,X 转发端口没有在本地侦听,因为 sshd 不在容器中 运行。将上面的行更改为:

<ip-of-host>:<no-of-display> MIT-MAGIC-COOKIE-1 <some number here>

本质上:删除/unix部分。

<ip-of-host>是sshd所在的IP地址运行.

如上设置 DISPLAY 变量。

所以错误是环境变量中的 DISPLAY 名称不是 "same" 作为 xauth list / .Xauthority 文件中的条目,客户端可以因此无法正确验证。

我切换回不受信任的 X11 转发设置。

sshd_config 文件中的 X11UseLocalhost no 设置很重要,因为传入连接将来自 "different" 机器(docker 容器)。

非常感谢@Lazarus535
我发现对我来说,将以下内容添加到我的 docker 命令中是有效的:
--volume="$HOME/.Xauthority:/root/.Xauthority:rw"
我发现了这个技巧 here
编辑:
正如 Lazarus 正确指出的那样,您还必须设置 --net=host 选项才能使其正常工作。

这适用于任何情况。

如果没有,请安装 xhost。然后,在bash、

export DISPLAY=:0.0
xhost +local:docker

在此 运行 之后,您的 docker run 命令(或您正在 运行ning 的任何 docker 命令)与 -e DISPLAY=$DISPLAY

它通常通过

工作

但是,如果您 运行 docker 使用的用户与用于 ssh -X 的用户不同,则进入服务器时使用;然后复制 Xauthority 仅有助于卷映射文件。

示例 - 我在 su -root 之后使用 alex user.Then 运行 docker 进入服务器并收到此错误

X11 connection rejected because of wrong authentication.

复制 .XAuthoirty 文件并像 那样映射后使其工作

cp /home/alex/.Xauthority .

docker run  -it --network=host --env DISPLAY=$DISPLAY  --privileged  \
 --volume="$HOME/.Xauthority:/root/.Xauthority:rw"  \
-v /tmp/.X11-unix:/tmp/.X11-unix --rm <dockerimage>

这里有更多关于布线的详细信息https://unix.stackexchange.com/a/604284/121634

一些澄清的言论。主机是A,本机是B

我编辑了这个 post 以记录我认为理论上应该可行但尚未经过测试的内容,以及我知道可行的内容

运行 docker 非交互

如果您的 docker 是 运行ning not interactively 并且 运行ning sshd,您可以使用 jumphosts 或 proxycommand 并将 x11 客户端指定为 运行。您应该 NOT volume 与容器共享您的 Xauthority 文件,并且共享 -e DISPLAY 可能对未来的 ssh 会话没有影响

因为您基本上有两个 sshd 服务器,所以下面的任何一个都应该开箱即用

如果你有7.3以上的openssh-client,可以使用下面的命令

ssh -X -J user-on-host@hostmachine,user-on-docker@dockercontainer xeyes

如果您的 openssh 客户端较旧,则语法为 (google 说代理命令中不需要 -X,但我很怀疑)

ssh -X -o ProxyCommand="ssh -W %h:%p user-on-host@hostmachine" user-on-docker@dockermachine xeyes

或 ssh -X 进入主机,然后 ssh -X 进入 docker.

在上述任一情况下,您应该与容器共享 .Xauthority

运行 docker 在 ssh 会话中交互

完成此操作的最简单方法是设置 --net=host 和 X11UseLocalhost yse。 如果您的 docker 是 运行ning sshd,您可以在本地计算机上打开第二个 ssh -X 会话并使用上面的 jumphost 方法。 如果您在 ssh 会话中启动它,您可以 -e DISPLAY=$DISPLAY 或在您进入时导出它。如果您附加到未使用此行的现有容器,则可能必须导出它。

将这些 docker args 用于 --net host 和 x11uselocalhost 是 ssh -X 到主机

   -e DISPLAY=$DISPLAY
   -v $HOME/.Xauthority:/home/same-as-dash-u-user/.Xauthority
   -u user

接下来是对一切工作原理和其他尝试方法的解释

关于 Xauthority

ssh -X/-Y 在主机 Xauthority 文件中设置一个会话密钥,然后设置一个侦听端口,在该端口上放置一个使用会话密钥的 x11 代理,并将其转换为兼容本地机器上的密钥。按照设计,.Xauthority 密钥在您的本地计算机和主机之间是不同的。如果你使用 jumphosts/proxycommand 主机和容器之间的密钥将再次彼此不同。如果您改为使用 ssh 隧道或直接 X11 连接,则必须与容器共享主机 Xauthority,在与容器共享 .Xauthority 的情况下,每个用户只能有一个活动会话,因为新会话会使通过修改主机 .Xauthority 使其仅适用于该会话的 ssh x11 代理

X11UserLocalhost 无理论##

即使 X11UseLocalhost 没有导致 x 服务器侦听通配符地址,但使用 --net host 我无法将容器显示重定向到 localhost:X.Y,其中 x 和原因来自主机 $DISPLAY

X11UseLocalhost 是的是最简单的方法

如果选择 X11UseLocalhost yes,主机上的 DISPLAY 变量变为 localhost:X:Y,这会导致 ssh x11 代理仅在本地主机端口 x 上侦听。

如果 X11UseLocalhost 为 no,主机上的 DISPLAY 变量变为主机的 hostname:X:Y,这会导致 xerver 侦听 0.0.0.0:6000+X 并导致 xclients 通过网络连接到指定的主机名。

这是理论上的,我还没有访问远程主机上的 docker 来测试这个

但这是简单的方法。我们通过将 DISPLAY 变量重定向到始终为本地主机来绕过它,并进行 docker 端口映射以将数据从容器上的 localhost:X+1.Y 移动到 localhost:X.Y在主机上,ssh 正在等待将 x 流量转发回本地机器。 +1 使我们无法 运行ning --net=host 或 --net=bridge 设置容器端口需要在 docker 文件中指定公开并使用 -p 命令发布端口。

在没有 ssh -X 的情况下手动设置所有内容

这仅适用于 --net 主机。这种方法在没有 xauth 的情况下也有效,因为我们直接通过管道连接到本地计算机上的 unix 域套接字

ssh 到没有-X 的主机

ssh -R6010:localhost:6010 user@host
start docker with -e DISPLAY=localhost:10.1 or export inside

在本地机器的另一个终端中

socat -d -d TCP-LISTEN:6010,fork UNIX-CONNECT:/tmp/.X11-unix/X0

在原始终端中 运行 xclients

如果容器是 net --bridged 并且您不能使用 docker 端口,请在容器上启用 sshd 并使用 jumphosts 方法