我运行的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。)
发布于 2014-08-16 05:13:25
有一种很好的半简单的方法可以从Docker容器中获得图形输出,而不必在容器中运行sshd守护进程。Docker可以在运行单个进程时提供裸机性能,在这种情况下,该进程应该是R。运行sshd守护进程可能会带来额外的开销。将sshd守护程序作为supervisor守护程序的子进程运行并不会改善这种情况。当一个人很好地利用绑定挂载时,这两个都可以省去。在构建了应该从中运行容器的镜像之后,我们启动了一个交互式容器,并将/tmp/.X11-unix文件夹绑定挂载到其中。我将陈述完整的命令,并详细解释它的作用:
运行-i -t的
docker --rm \
-i建立了一个交互会话;-t分配了一个伪tty;--rm使这个容器成为短暂的-e DISPLAY=$DISPLAY \
:0)-u docker \
-u指定进程应该由用户(这里是docker)运行,而不是由根用户运行。此步骤很重要(VI.)!-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-v bind将驻留在本地计算机的/tmp/.X11-unix中的X11套接字挂载到容器的/tmp/.X11-unix中,并且:ro将套接字设置为只读。--名称=“rdev”ubuntu-r R
--name=""指定容器的名称(此处为rdev);您希望从中运行容器的映像(此处为ubuntu-r);您希望在容器中运行的进程(此处为R)。(仅当您尚未为映像设置默认CMD或ENTRYPOINT时,才需要指定进程的最后一步。)发出此命令后,您应该会看到漂亮的R start输出。如果您尝试使用demo(graphics)查看图形输出是否已经正常工作,您会注意到它不工作。这是因为Xsecurity扩展阻止您访问套接字。现在,您可以在本地计算机上输入xhost +,然后在容器中再次尝试demo(graphics)。您现在应该有了图形输出。但是,强烈建议您使用此方法,因为您允许当前连接到的任何远程主机访问您的xsocket。只要您只与单用户系统交互,这可能在某种程度上是合理的,但一旦涉及多个用户,这将是绝对不安全的!因此,您应该使用一种不太危险的方法。一个不错的方法是使用服务器解释
xhost +si:localuser:username它可用于指定单个本地用户(请参阅man xhost)。这意味着username应该是在本地机器上运行X11服务器并运行docker容器的用户的名称。这也是为什么在运行容器时指定用户很重要的原因。最后但并非最不重要的是,始终存在更复杂的解决方案,即使用xauth和.Xauthority文件授予对X11套接字的访问权限(请参阅man xauth)。然而,这也需要更多地了解X是如何工作的。
这可能产生的积极影响可以从为了实现所需的目的而需要运行的进程的数量中看出。
(1)容器内运行supervisor和sshd:
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发布于 2016-11-16 23:31:25
这显然是我到目前为止找到的最好的解决方案:
https://stackoverflow.com/a/25280523/1353930 (所有功劳都归功于Jürgen Weigert)
优势:
发布于 2021-09-16 21:40:54
根据lord.垃圾的回答,我们可以转发主机的X11套接字。同样,我们可以根据上面分享的Jürgen Weigert非常好的想法,在docker镜像创建时创建一个用户(感谢Hugo/Daniel)。但是,如果我们不想修改xhost ACL或创建静态绑定到某个用户凭据的映像,该怎么办?我们还可以做一个额外的改进:
从主机shell运行容器转发user-id/group时:
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创建包装器脚本并将其设置为容器的入口点。在脚本中,使用主机的user-id/group-id创建一个新用户,然后使用sudo "as host“运行目标应用程序:
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的解决方案,并且可以在任何地方运行。
https://stackoverflow.com/questions/25281992
复制相似问题