【问题标题】:Alternatives to ssh X11-forwarding for Docker containersDocker 容器的 ssh X11 转发的替代方案
【发布时间】:2021-09-17 06:04:44
【问题描述】:

我正在运行一个 Docker 容器,主要作为R 语言的独立开发环境。 (这里R 的用法与帖子的其余部分是正交的,即您可以假设任何可以在repl-session 中运行的通用程序。)很多时候这将涉及到诸如绘图之类的事情,制作图形等;我需要看看 这些。因此,我更愿意选择显示我在容器中创建的图形。到目前为止,我是这样做的。首先我创建一个Dockerfile。省略最相关的琐碎步骤:

# Set root passwd 
RUN echo "root:test" | chpasswd

# Add user so that container does not run as root 
RUN useradd -m docker 
RUN echo "docker:test" | chpasswd 
RUN usermod -s /bin/bash docker 
RUN usermod -aG sudo docker 
ENV HOME /home/docker

RUN mkdir /var/run/sshd 
RUN mkdir -p /var/log/supervisor

# copy servisord.conf which lists the processes to be spawned once this 
# container is started (currently only one: sshd) 
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 22 
CMD ["/usr/bin/supervisord"]

我构建映像,然后使用以下命令启动容器:

docker run -d -p 127.0.0.1:5000:22 -h ubuntu-r -v /home/chb/files/Data:/home/docker/Data -P --name="rdev" ubuntu-r

然后可以 ssh 进入我的容器:

ssh -X docker@localhost -p 5000.

这会给我我想要的。但我想知道是否有另一种更资源友好的方式从容器获取图形/GUI 输出? (如果可能,我希望解决方案不涉及vnc。)

【问题讨论】:

标签: user-interface docker


【解决方案1】:

有一种从 Docker 容器,无需在内部运行 sshd 守护进程 容器。 Docker 可以在单机运行时提供裸机性能 在这种情况下应该是R的进程。运行 sshd 守护进程 将,尽管它可能是微不足道的,会引入额外的开销。这不是 通过将 sshd 守护进程作为 主管守护进程。当一个人善用时,两者都可以省去 绑定坐骑。在构建容器应该使用的图像之后 要运行,我们启动一个交互式容器并绑定挂载 /tmp/.X11-unix 文件夹放入其中。我将陈述完整的命令和 详细解释它的作用:

docker run -i -t --rm \

  • -i 设置交互会话; -t 分配一个伪 tty; --rm 使这个容器变得短暂

-e 显示=$显示\

  • 将主机显示设置为本地机器显示(通常为:0

-u 码头工人\

  • -u 指定进程应由用户(此处为 docker)而不是 root 运行。这一步很重要 (v.i.)!

-v /tmp/.X11-unix:/tmp/.X11-unix:ro \

  • -vbind 将驻留在本地计算机上的/tmp/.X11-unix 中的X11 套接字安装到容器中的/tmp/.X11-unix 中,:ro 使套接字只读。

--name="rdev" ubuntu-r R

  • --name=""指定容器的名称(这里rdev);您要从中运行容器的映像(此处为ubuntu-r);你想在容器中运行的进程(这里是R)。 (仅当您没有为图像设置默认 CMDENTRYPOINT 时,才需要指定进程的最后一步。)

发出此命令后,您应该看到漂亮的R 开始输出。如果你想试试demo(graphics) 看看是否有图形 输出已经在工作你会注意到它不是。那是因为 Xsecurity 扩展阻止您访问套接字。你 现在可以在本地机器上输入xhost + 并尝试demo(graphics) 再次你的容器。您现在应该有图形输出。这种方法 但是,强烈建议您不要访问您的 xsocket 您当前连接到的任何远程主机。只要你只是 与单用户系统交互这可能在某种程度上是合理的,但 一旦涉及多个用户,这绝对是 不安全!因此,您应该使用危险性较小的方法。一个好办法是 使用服务器解释

xhost +si:localuser:username

可用于指定单个本地用户(请参阅man xhost)。这表示 username 应该是运行 X11 服务器的用户名 您的本地机器并运行 docker 容器。这也是 为什么在运行时指定用户很重要的原因 容器。最后但并非最不重要的一点是,总是有更复杂的解决方案 使用xauth.Xauthority 文件授予对X11 套接字的访问权限 (见man xauth)。然而,这也将涉及更多的知识 X 的工作原理。

这可以产生的积极影响可以从进程数量中看出 需要运行以实现所需的目标。

(1) supervisorsshd 在容器中运行:

UID                 PID                 PPID                C                STIME               TTY                 TIME                CMD
root                4564                718                 1                18:16               ?                   00:00:00            /usr/bin/python /usr/bin/supervisord
root                4576                4564                0                18:16               ?                   00:00:00            /usr/sbin/sshd

当通过ssh 登录并运行R 时:

UID                 PID                 PPID                C                 STIME               TTY                 TIME                CMD
root                4564                718                 0                 18:16               ?                   00:00:00            /usr/bin/python /usr/bin/supervisord
root                4576                4564                0                 18:16               ?                   00:00:00            /usr/sbin/sshd
root                4674                4576                0                 18:17               ?                   00:00:00            sshd: docker [priv]   
chb                 4725                4674                0                 18:18               ?                   00:00:00            sshd: docker@pts/0
chb                 4728                4725                1                 18:18               pts/0               00:00:00            -bash

(2) 使用绑定挂载方式:

UID                 PID                 PPID                C                 STIME               TTY                 TIME                CMD
chb                 4356                718                 0                 18:12               pts/4               00:00:00            /usr/local/lib/R/bin/exec/R --no-save --no-restore

【讨论】:

  • 好东西,谢谢 :-) 您的解决方案与那个解决方案相比如何:olivier.barais.fr/blog/posts/2014.08.26/…(不同的 xhost 命令,无 -u 选项)
  • 谢谢。 :) 简而言之:她/他使用容器主机名仅授予对特定受信任 docker 容器的访问权限。另一方面,我向受信任的用户授予访问权限,从而授予她/他正在启动的所有容器。这是因为容器中的 uid 与主机上的相同。
  • 好的,我明白了,干杯 =) 如果我运行多个容器,那么信任用户可能更方便。但我猜它也不太安全。 -u 选项呢?没有它,您的解决方案似乎可以工作;我错过了什么吗?
  • 这有两个(?)原因:(1)-u 选项只是增加了另一层安全性。 docker 守护进程现在在主机上以 root 身份运行。因此,如果容器中的进程逃逸到主机,它可能会造成很大的损害。如果容器中的进程作为用户进程运行,这会以某种方式得到缓解。 (2) 授予 x-socket 的 root 访问权限不是一个好主意。换一种说法:应该应用最小特权原则。
  • 这似乎不是一个可复制和可粘贴的答案。 -u 命令给出“来自守护进程的错误响应:无法启动容器 X:[8] 系统错误:无法找到用户 docker”错误。尽管我当前正在运行的用户是 'docker' 并且在 Dockerfile 中还定义了一个 'docker' 用户。
【解决方案2】:

这显然是我迄今为止找到的最佳解决方案:

https://stackoverflow.com/a/25280523/1353930(所有功劳归于 Jürgen Weigert)

优点:

  • 在 docker 内部,UID 不相关(但我仍然建议不要使用 root)
  • 在主机上,您不必更改安全设置 (xhost +)

【讨论】:

    【解决方案3】:

    根据 lord.garbage 的回答,我们可以转发主机的 X11 套接字。同样,我们可以按照 Jürgen Weigert 上面分享的非常好的想法在 docker 镜像创建时创建一个用户(感谢 Hugo/Daniel。)但是,如果我们不想修改 xhost ACL 或创建静态绑定到的镜像怎么办?一个用户的凭据?我们还可以进行另一项改进:

    从主机外壳运行容器时转发用户 ID/组:

    XSOCK=/tmp/.X11-unix
    docker run -it --rm \
        -e HOST_USER=$(id -u) \
        -e HOST_GROUP=$(id -g) \
        -e HOST_USER_NAME=$(whoami) \
        -e DISPLAY=$DISPLAY \
        -v $XSOCK:$XSOCK \
        my_container:latest
    

    创建包装脚本并将其设置为容器的入口点。在您的脚本中使用主机的用户 ID/组 ID 创建一个新用户,然后使用 sudo “作为主机”运行您的目标应用程序:

    groupadd -o -g $HOST_GROUP docker
    useradd -d /home/$HOST_USER_NAME -s /bin/bash -u $HOST_USER -g docker $HOST_USER_NAME
    sudo -u $HOST_USER_NAME bash -c "<some bash commands etc.>"
    

    由于程序将以正确的用户执行,因此无需更改访问控制。感谢 Jürgen Weigert 的好主意,以及这个小小的改进,我们有了一个不需要 xhost 并且可以在任何地方运行的解决方案。

    【讨论】:

      猜你喜欢
      • 2015-12-30
      • 2017-09-22
      • 2017-06-30
      • 2021-07-27
      • 1970-01-01
      • 2013-07-06
      • 1970-01-01
      • 2013-03-09
      • 2020-10-31
      相关资源
      最近更新 更多