用于Docker容器的ssh X11-forwarding的替代scheme
我正在运行一个Docker容器,主要是作为R
语言的一个独立的开发环境。 (这里的R
的用法与post的其余部分是正交的,也就是说,你可以假定任何可以在repl
session中运行的通用程序)。很多时候这将涉及到做绘图,制作graphics等等的东西; 我需要看看这些。 因此,我宁愿有显示在我的容器中创build的graphics的选项。 到目前为止,我是这样做的。 首先我创build一个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.
这会给我想要的。 但我想知道是否有另一种更容易从容器获取graphics/ GUI输出的资源? (我更喜欢,如果可能的话,解决scheme不会涉及vnc
。)
从Docker容器获取graphics输出是一种不错的和半简单的方法,无需在容器内部运行sshd
守护进程。 在运行单个进程时,Docker可以提供裸机性能,在这种情况下应该是R
运行一个sshd守护进程可能会带来额外的开销。 通过运行sshd守护进程作为supervisor守护进程的subprocess,这并不是一件好事。 当使用绑定安装时,两者都可以省略。 在构build应该运行容器的映像之后,我们启动一个交互容器并绑定/tmp/.X11-unix
文件夹。 我将陈述完整的命令并详细解释它的作用:
docker运行-i -t –rm \
-
-i
build立一个互动的会议;-t
分配一个伪tty;--rm
使这个容器是短暂的
-e DISPLAY = $ DISPLAY \
- 将主机显示设置为本地机器显示(通常为
:0
)
-udocker工人\
-
-u
指定进程应该由用户(这里是docker
)而不是root来运行。 这一步很重要(六)!
-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-
-v
绑定将驻留在本地计算机上的/tmp/.X11-unix
中的X11
套接字挂载到/tmp/.X11-unix
中的/tmp/.X11-unix
中:ro
使得套接字只读。
–name =“rdev”ubuntu-r R
-
--name=""
指定容器的名字(这里是rdev
); 你想运行容器的映像(这里是ubuntu-r
); 你想在容器中运行的过程(这里是R
)。 (只有当您没有为您的图像设置默认CMD
或ENTRYPOINT
,才需要指定过程的最后一步。)
发出这个命令后,你应该看看漂亮的R
启动输出。 如果你想试试看demo(graphics)
是否graphics输出已经工作,你会注意到它不是。 这是因为Xsecurity
扩展阻止您访问套接字。 您现在可以在本地机器上键入xhost +
并再次尝试在容器中demo(graphics)
。 你现在应该有graphics输出。 然而,这种方法是强烈的,因为你允许访问你的xsocket到你当前连接的任何远程主机。 只要你只与单用户系统交互,这可能是合理的,但只要有多个用户参与,这绝对是不安全的! 因此,你应该使用一个不太危险的方法。 一个好方法是使用解释的服务器
xhost +si:localuser:username
它可以用来指定一个本地用户(见man xhost
)。 这意味着username
应该是在本地机器上运行X11
服务器并运行docker容器的用户的名字。 这也是为什么在运行容器时指定用户非常重要的原因。 最后但并非最不重要的是,总是有更复杂的解决scheme来使用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
这显然是我迄今发现的最佳解决scheme:
https://stackoverflow.com/a/25280523/1353930 (所有学分去JürgenWeigert)
优点:
- 在docker里面,UID不相关(但是我还是build议不要使用root)
- 在主机上,您不必更改安全设置(
xhost +
)