如何在Linux Docker容器中运行GUI应用程序?
是否有任何图像设置vncserver或其他东西,以便您可以-例如-在Firefox周围添加额外的加速沙箱?
如何在Linux Docker容器中运行GUI应用程序?
是否有任何图像设置vncserver或其他东西,以便您可以-例如-在Firefox周围添加额外的加速沙箱?
当前回答
共享主机显示:0,正如在其他一些回答中所述,有两个缺点:
由于某些X安全漏洞,它打破了容器隔离。例如,可以使用xev或xinput进行键盘记录,使用xdotool远程控制主机应用程序。 由于X扩展MIT-SHM缺少共享内存,应用程序可能会出现呈现故障和糟糕的RAM访问错误。(也可以通过隔离降级选项——ipc=host进行修复)。
下面是一个在Xephyr中运行docker映像的示例脚本,可以解决这个问题。
当docker应用程序运行在嵌套的X服务器上时,它避免了X安全泄漏。 MIT-SHM关闭,避免RAM访问失败。 容器安全性通过——cap-drop ALL——security-opt no-new-privileges得到改进。容器用户也不是root用户。 创建一个X cookie来限制对Xephyr显示的访问。
脚本需要一些参数,第一个是在Xephyr中运行的主机窗口管理器,第二个是docker映像,第三个是可选的 要执行的映像命令。 要在docker中运行桌面环境,请使用“:”而不是主机窗口管理器。
关闭Xephyr窗口将终止docker容器应用程序。终止停靠的应用程序关闭Xephyr窗口。
例子:
x11docker/lxde pcmanfm . xphyrdocker "openbox——sm-disable Xephyrdocker: x11docker/lxde Xephyrdocker xfwm4——device /dev/snd jess/nes /games/zelda.rom
xephyrdocker script:
#! /bin/bash
#
# Xephyrdocker: Example script to run docker GUI applications in Xephyr.
#
# Usage:
# Xephyrdocker WINDOWMANAGER DOCKERIMAGE [IMAGECOMMAND [ARGS]]
#
# WINDOWMANAGER host window manager for use with single GUI applications.
# To run without window manager from host, use ":"
# DOCKERIMAGE docker image containing GUI applications or a desktop
# IMAGECOMMAND command to run in image
#
Windowmanager="$1" && shift
Dockerimage="$*"
# Container user
Useruid=$(id -u)
Usergid=$(id -g)
Username="$(id -un)"
[ "$Useruid" = "0" ] && Useruid=1000 && Usergid=1000 && Username="user$Useruid"
# Find free display number
for ((Newdisplaynumber=1 ; Newdisplaynumber <= 100 ; Newdisplaynumber++)) ; do
[ -e /tmp/.X11-unix/X$Newdisplaynumber ] || break
done
Newxsocket=/tmp/.X11-unix/X$Newdisplaynumber
# cache folder and files
Cachefolder=/tmp/Xephyrdocker_X$Newdisplaynumber
[ -e "$Cachefolder" ] && rm -R "$Cachefolder"
mkdir -p $Cachefolder
Xclientcookie=$Cachefolder/Xcookie.client
Xservercookie=$Cachefolder/Xcookie.server
Xinitrc=$Cachefolder/xinitrc
Etcpasswd=$Cachefolder/passwd
# command to run docker
# --rm created container will be discarded.
# -e DISPLAY=$Newdisplay set environment variable to new display
# -e XAUTHORITY=/Xcookie set environment variable XAUTHORITY to provided cookie
# -v $Xclientcookie:/Xcookie:ro provide cookie file to container
# -v $NewXsocket:$NewXsocket:ro Share new X socket of Xephyr
# --user $Useruid:$Usergid Security: avoid root in container
# -v $Etcpasswd:/etc/passwd:ro /etc/passwd file with user entry
# --group-add audio Allow access to /dev/snd if shared with '--device /dev/snd'
# --cap-drop ALL Security: disable needless capabilities
# --security-opt no-new-privileges Security: forbid new privileges
Dockercommand="docker run --rm \
-e DISPLAY=:$Newdisplaynumber \
-e XAUTHORITY=/Xcookie \
-v $Xclientcookie:/Xcookie:ro \
-v $Newxsocket:$Newxsocket:rw \
--user $Useruid:$Usergid \
-v $Etcpasswd:/etc/passwd:ro \
--group-add audio \
--env HOME=/tmp \
--cap-drop ALL \
--security-opt no-new-privileges \
$(command -v docker-init >/dev/null && echo --init) \
$Dockerimage"
echo "docker command:
$Dockercommand
"
# command to run Xorg or Xephyr
# /usr/bin/Xephyr an absolute path to X server executable must be given for xinit
# :$Newdisplaynumber first argument has to be new display
# -auth $Xservercookie path to cookie file for X server. Must be different from cookie file of client, not sure why
# -extension MIT-SHM disable MIT-SHM to avoid rendering glitches and bad RAM access (+ instead of - enables it)
# -nolisten tcp disable tcp connections for security reasons
# -retro nice retro look
Xcommand="/usr/bin/Xephyr :$Newdisplaynumber \
-auth $Xservercookie \
-extension MIT-SHM \
-nolisten tcp \
-screen 1000x750x24 \
-retro"
echo "X server command:
$Xcommand
"
# create /etc/passwd with unprivileged user
echo "root:x:0:0:root:/root:/bin/sh" >$Etcpasswd
echo "$Username:x:$Useruid:$Usergid:$Username,,,:/tmp:/bin/sh" >> $Etcpasswd
# create xinitrc
{ echo "#! /bin/bash"
echo "# set environment variables to new display and new cookie"
echo "export DISPLAY=:$Newdisplaynumber"
echo "export XAUTHORITY=$Xclientcookie"
echo "# same keyboard layout as on host"
echo "echo '$(setxkbmap -display $DISPLAY -print)' | xkbcomp - :$Newdisplaynumber"
echo "# create new XAUTHORITY cookie file"
echo ":> $Xclientcookie"
echo "xauth add :$Newdisplaynumber . $(mcookie)"
echo "# create prepared cookie with localhost identification disabled by ffff,"
echo "# needed if X socket is shared instead connecting over tcp. ffff means 'familiy wild'"
echo 'Cookie=$(xauth nlist '":$Newdisplaynumber | sed -e 's/^..../ffff/')"
echo 'echo $Cookie | xauth -f '$Xclientcookie' nmerge -'
echo "cp $Xclientcookie $Xservercookie"
echo "chmod 644 $Xclientcookie"
echo "# run window manager in Xephyr"
echo $Windowmanager' & Windowmanagerpid=$!'
echo "# show docker log"
echo 'tail --retry -n +1 -F '$Dockerlogfile' 2>/dev/null & Tailpid=$!'
echo "# run docker"
echo "$Dockercommand"
} > $Xinitrc
xinit $Xinitrc -- $Xcommand
rm -Rf $Cachefolder
这个脚本在x11docker wiki上维护。 更高级的脚本是x11docker,它还支持GPU加速、网络摄像头和打印机共享等功能。
其他回答
我通过以下步骤从USB摄像头使用opencv在docker中运行视频流:
Let docker access the X server xhost +local:docker Create the X11 Unix socket and the X authentication file XSOCK=/tmp/.X11-unix XAUTH=/tmp/.docker.xauth Add proper permissions xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge - Set the Qt rendering speed to "native", so it doesn't bypass the X11 rendering engine export QT_GRAPHICSSYSTEM=native Tell Qt to not use MIT-SHM (shared memory) - that way it should be also safer security-wise export QT_X11_NO_MITSHM=1 Update the docker run command docker run -it \ -e DISPLAY=$DISPLAY \ -e XAUTHORITY=$XAUTH \ -v $XSOCK:$XSOCK \ -v $XAUTH:$XAUTH \ --runtime=nvidia \ --device=/dev/video0:/dev/video0 \ nvcr.io/nvidia/pytorch:19.10-py3
注意:当你完成项目时,返回默认值的访问控制- xhost -local:docker
更多细节:使用GUI的Docker
图片来源:使用Tensorflow、OpenCV和Docker进行实时和视频处理对象检测
你可以简单地安装一个vncserver和Firefox:)
我推了一个图像,vnc/firefox,在这里:docker拉creack/firefox-vnc
图片是用Dockerfile制作的:
# Firefox over VNC
#
# VERSION 0.1
# DOCKER-VERSION 0.2
FROM ubuntu:12.04
# Make sure the package repository is up to date
RUN echo "deb http://archive.ubuntu.com/ubuntu precise main universe" > /etc/apt/sources.list
RUN apt-get update
# Install vnc, xvfb in order to create a 'fake' display and firefox
RUN apt-get install -y x11vnc xvfb firefox
RUN mkdir ~/.vnc
# Setup a password
RUN x11vnc -storepasswd 1234 ~/.vnc/passwd
# Autostart firefox (might not be the best way to do it, but it does the trick)
RUN bash -c 'echo "firefox" >> /.bashrc'
这将创建一个运行VNC的Docker容器,密码为1234:
对于Docker 18或更新版本:
docker run -p 5900:5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create
对于Docker 1.3或更新版本:
docker run -p 5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create
对于1.3版本之前的Docker:
docker run -p 5900 creack/firefox-vnc x11vnc -forever -usepw -create
您也可以使用subuser: https://github.com/timthelion/subuser
这允许你在docker中打包许多gui应用程序。到目前为止,Firefox和emacs已经进行了测试。然而,在firefox中,webGL却不能正常工作。铬根本不起作用。
编辑:声音工作!
EDIT2:自从我第一次发布这篇文章以来,subbuser已经取得了很大的进步。我现在有了一个subuser.org网站,以及一个通过XPRA桥接连接到X11的新安全模型。
你可以允许Docker用户(这里是root)访问X11显示:
XSOCK=/tmp/.X11-unix
xhost +SI:localuser:root
docker run -t -i --rm -v $XSOCK:$XSOCK:ro -e DISPLAY=unix$(DISPLAY) image
xhost -SI:localuser:root
这里有一个轻量级的解决方案,可以避免在容器上安装任何X服务器,vnc服务器或sshd守护进程。它在简单中得到的好处,却在安全和隔离中失去了。
它假设您使用带有X11转发的ssh连接到主机。
在主机的sshd配置中添加该行
X11UseLocalhost no
因此,主机上转发的X服务器端口在所有接口上都是开放的(不仅仅是lo),特别是在Docker虚拟接口docker0上。
容器在运行时需要访问. xauthority文件,以便连接到服务器。为此,我们定义了一个只读卷,指向主机上的主目录(可能不是一个明智的主意!),并相应地设置XAUTHORITY变量。
docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority
这还不够,我们还必须从主机传递DISPLAY变量,但是用ip代替主机名:
-e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")
我们可以定义一个别名:
alias dockerX11run='docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority -e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")'
然后像这样测试:
dockerX11run centos xeyes