【问题标题】:X11 forwarding of a GUI app running in docker在 docker 中运行的 GUI 应用程序的 X11 转发
【发布时间】:2017-11-09 19:05:17
【问题描述】:

首先:我已经阅读了关于 SO 的类似问题的答案,但没有一个有效。

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

情况:

  • 带有 GUI 的应用程序在 Arch Linux 下的 docker 容器 (CentOS 7.1) 中运行。 (机器 A)
  • 机器 A 连接了一个监视器。
  • 我想在我的 Arch Linux 客户端机器上通过 X11 转发访问这个 GUI。 (机器 B)

什么有效:

  • GUI 在机器 A 上本地运行(在 Docker 容器中挂载了 /tmp/.X11-unix)。
  • X11 转发在 docker 之外运行的任何应用程序(X11 转发已设置并正常运行以供非 docker 使用)。
  • 我什至可以在远程登录时切换用户,将.Xauthority 文件复制给其他用户,X11 转发也能正常工作。

一些设置信息:

  • Docker 网络已“桥接”。
  • 容器可以到达主机(防火墙已打开)。
  • 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 变量可能需要调整。

【问题讨论】:

    标签: authentication docker x11-forwarding


    【解决方案1】:

    好的,事情是这样的:

    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 部分。

    &lt;ip-of-host&gt; 是运行 sshd 的 IP 地址。

    如上设置 DISPLAY 变量。

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

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

    然而,sshd_config 文件中的X11UseLocalhost no 设置很重要,因为传入的连接将来自“不同”的机器(docker 容器)。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 您好!很棒的发现!但我怀疑这仅在您添加--net=host 标志时才有效?因为那时应用程序“认为”它在本地网络上运行。但是我不喜欢host 网络选项,如果 docker 在虚拟网络中有自己的 IP,我更喜欢。
      • 你是绝对正确的--net=host也必须添加
      • 在 Docker 中运行 GUI 之前,我从未遇到过这个问题。这次我通过两台服务器链接 X11 并得到这个权限错误。为其他人附加完整命令docker run -it --network=host --env DISPLAY=127.0.0.1:11.0 --privileged --volume="$HOME/.Xauthority:/root/.Xauthority:rw" -v /tmp/.X11-unix:/tmp/.X11-unix --rm &lt;idockerimage&gt;
      【解决方案3】:

      这适用于任何情况。

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

      export DISPLAY=:0.0
      xhost +local:docker
      

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

      【讨论】:

      • 从 docker 内的应用程序获取 GUI 已经解决,我的问题专门处理了添加的 ssh X11 转发步骤。我现在就试试这个。
      • 对我不起作用。您尚未安装 /tmp/X11-unix (X11 域套接字),并且默认情况下通常通过虚拟网络附加一个新的 docker 容器。我看不到应用程序如何找到在 docker 之外运行的 X11 实例。请说清楚。谢谢。
      【解决方案4】:

      它通常通过https://stackoverflow.com/a/61060528/429476工作

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

      示例 - 我使用 alex 用户 ssh 进入服务器。然后在 su -root 之后运行 docker 并收到此错误

      X11 connection rejected because of wrong authentication.

      复制 .XAuthoirty 文件并将其映射为 https://stackoverflow.com/a/51209546/429476 后使其工作

      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

      【讨论】:

        【解决方案5】:

        一些澄清说明。主机是A,本机是B

        我编辑了这篇文章,以说明我认为理论上应该可行但尚未经过测试的事情,以及我知道可行的事情

        以非交互方式运行 docker

        如果你的 docker 不是以交互方式运行并运行 sshd,你可以使用 jumphosts 或 proxycommand 并指定要运行的 x11 客户端。您应该与容器共享您的 Xauthority 文件,并且共享 -e DISPLAY 可能对未来的 ssh 会话没有影响

        由于您基本上有两个 sshd 服务器,因此以下任何一个都应该开箱即用

        如果你的 openssh-client 版本高于 7.3,可以使用以下命令

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

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

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

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

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

        在 ssh 会话中以交互方式运行 docker

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

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

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

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

        关于 Xauthority

        ​​>

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

        X11UserLocalhost 没有理论##

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

        X11UseLocalhost 是的,简单的方法

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

        如果 X11UseLocalhost 为否,则主机上的 DISPLAY 变量将成为主机的主机名:X:Y,这会导致 xerver 在 0.0.0.0:6000+X 上侦听并导致 xclients 通过网络访问指定的主机名.

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

        但这是最简单的方法。我们通过将 DISPLAY 变量重定向为始终为 localhost 来绕过它,并进行 docker 端口映射以将数据从容器上的 localhost:X+1.Y 移动到主机上的 localhost:XY,其中 ssh 正在等待转发 x 流量回到本地机器。 +1 使我们无法运行 --net=host 或 --net=bridge 设置容器端口需要在 dockerfile 中指定暴露并使用 -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 方法

        【讨论】:

        • X11UseLocalhost 设置在哪里,我没有在任何命令中看到它?是宿主机还是容器配置的一部分?
        猜你喜欢
        • 2016-08-01
        • 2017-06-30
        • 1970-01-01
        • 2018-04-16
        • 2023-03-05
        • 1970-01-01
        • 2015-03-29
        • 2013-04-24
        相关资源
        最近更新 更多