docker 中的 GUI 应用程序的 X11 转发 运行
X11 forwarding of a GUI app running in docker
首先:我已经在 SO 上阅读了类似问题的答案,但是 none 有效。
重要提示:下面的答案仍然有效,但可能会跳到最后寻找替代方案。
情况:
- 带 GUI 的应用程序 运行 在 Arch Linux 下的 docker 容器 (CentOS 7.1) 中。 (机器A)
- 机器 A 连接了显示器。
- 我想在我的 Arch Linux 客户端机器上通过 X11 转发访问这个 GUI。 (机器 B)
什么有效:
- GUI 在机器 A 上本地工作(/tmp/.X11-unix 安装在 Docker 容器中)。
- 运行 docker 之外的任何应用程序的 X11 转发(X11 转发已设置并且 运行 适合非 docker 使用)。
- 我什至可以在远程登录时切换用户,将
.Xauthority
文件复制到另一个用户,X11 转发也可以。
一些设置信息:
- Docker 网络是 'bridged'。
- 容器可以访问主机(防火墙已打开)。
DISPLAY
变量在容器中设置(到 host-ip-addr:10.0 因为 sshd 正在侦听的 TCP 端口 6010)。
- 到 X 转发端口 (6010) 的数据包正在从容器到达主机(
tcpdump
选中)。
什么不起作用:
- Docker 应用程序的 X11 转发
- 错误:
X11 connection rejected because of wrong authentication.
xterm: Xt error: Can't open display: host-ip-addr:10.0
我尝试过的事情:
- 在机器 B
上使用 ssh -Y
选项启动客户端 ssh
- 将
"X11ForwardTrusted yes"
放入机器 B 的 ssh_config 中
xhost +
(因此允许任何客户端连接)机器 B
- 将
Host *
放入机器 B 的 ssh_config 中
- 将
X11UseLocalhost no
放入机器 A 的 sshd_config 中(以允许非本地主机客户端)
- 从机器 A
上的登录用户使用 xauth add
在容器中添加 X 身份验证令牌
- 只需将工作用户的
.Xauthority
文件复制到容器中
- 使 shure
.Xauthority
文件具有正确的权限和所有者
我怎样才能禁用所有 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 方法
首先:我已经在 SO 上阅读了类似问题的答案,但是 none 有效。
重要提示:下面的答案仍然有效,但可能会跳到最后寻找替代方案。
情况:
- 带 GUI 的应用程序 运行 在 Arch Linux 下的 docker 容器 (CentOS 7.1) 中。 (机器A)
- 机器 A 连接了显示器。
- 我想在我的 Arch Linux 客户端机器上通过 X11 转发访问这个 GUI。 (机器 B)
什么有效:
- GUI 在机器 A 上本地工作(/tmp/.X11-unix 安装在 Docker 容器中)。
- 运行 docker 之外的任何应用程序的 X11 转发(X11 转发已设置并且 运行 适合非 docker 使用)。
- 我什至可以在远程登录时切换用户,将
.Xauthority
文件复制到另一个用户,X11 转发也可以。
一些设置信息:
- Docker 网络是 'bridged'。
- 容器可以访问主机(防火墙已打开)。
DISPLAY
变量在容器中设置(到 host-ip-addr:10.0 因为 sshd 正在侦听的 TCP 端口 6010)。- 到 X 转发端口 (6010) 的数据包正在从容器到达主机(
tcpdump
选中)。
什么不起作用:
- Docker 应用程序的 X11 转发
- 错误:
X11 connection rejected because of wrong authentication.
xterm: Xt error: Can't open display: host-ip-addr:10.0
我尝试过的事情:
- 在机器 B 上使用
- 将
"X11ForwardTrusted yes"
放入机器 B 的 ssh_config 中 xhost +
(因此允许任何客户端连接)机器 B- 将
Host *
放入机器 B 的 ssh_config 中 - 将
X11UseLocalhost no
放入机器 A 的 sshd_config 中(以允许非本地主机客户端) - 从机器 A 上的登录用户使用
- 只需将工作用户的
.Xauthority
文件复制到容器中 - 使 shure
.Xauthority
文件具有正确的权限和所有者
ssh -Y
选项启动客户端 ssh
xauth add
在容器中添加 X 身份验证令牌
我怎样才能禁用所有 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 方法