如何在Docker容器中运行GUI应用程序?

是否有任何设置vncserver的图像或类似的东西,以便您可以-例如-在Firefox周围添加一个额外的speedbump沙箱?

评论

这个问题似乎仅与Linux有关(基于年龄和答案的内容),与Windows不相关。如果是这样,我们可以编辑标题以澄清这一点吗?谢谢

相关:如何使Xvfb显示可见?

有关某些想法,请查看《 HPC可视化容器用户指南》。

#1 楼

您可以简单地与Firefox一起安装vncserver :)

我在这里推送了一个图像vnc / firefox:docker pull 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且密码为1234的Docker容器:

对于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


评论


我将如何使用VNC客户端远程查看此内容?键入IP +端口似乎无效。

–user94154
13年7月30日在0:42

首先,您需要检查分配的端口(通过docker inspect 或只是docker ps,然后使用刚刚找到的端口连接到主机的ip。

–裂纹
13年7月30日在0:54

creackfirefox-vnc映像失败,并出现以下错误:输入VNC密码:stty:标准输入:设备fgets的ioctl不正确:无此类文件或目录stty:标准输入:设备x11vnc的ioctl不正确-usepw:找不到要使用的密码。

– alfonsodev
2014年11月11日下午13:35

很好地使用Docker>通过Docker运行GUI应用fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker

–丹尼斯C
2014年11月17日下午6:22

没有用户名,密码会在答案中明确指出,任何vnc客户端都可以。就我而言,我喜欢本机osx。 (从Finder中,按Command + K并连接到vnc:// :<容器暴露端口>)

–裂纹
2014年11月25日15:08

#2 楼

Xauthority成为新系统的问题。我可以在运行Docker容器之前放弃使用xhost +进行的任何保护,也可以传入准备充分的Xauthority文件。典型的Xauthority文件是特定于主机名的。使用docker时,每个容器可以具有不同的主机名(使用docker run -h设置),但是即使将容器的主机名设置为与主机系统相同也不能解决我的问题。 xeyes(我喜欢这个示例)只会忽略魔术cookie,并且不会将凭据传递给服务器。因此,我们收到一条错误消息“未指定协议,无法打开显示”。

可以用某种方式编写Xauthority文件,这样主机名就无关紧要。
我们需要设置身份验证系列转到“ FamilyWild”。我不确定xauth是否为此使用了正确的命令行,因此这是结合xauth和sed来执行此操作的示例。我们需要更改nlist输出的前16位。 FamilyWild的值为65535或0xffff。

docker build -t xeyes - << __EOF__
FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes
__EOF__
XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
xauth nlist :0 | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
docker run -ti -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH -e XAUTHORITY=$XAUTH xeyes


评论


请注意,-v $ XSOCK:$ XSOCK -v $ XAUTH:$ XAUTH可以缩写为-v $ XSOCK -v $ XAUTH

–彼得·亚历山大·克米洛夫斯基(Piotr Aleksander Chmielowski)
16年4月13日在14:37

对我不起作用的@ PiotrAleksanderChmielowski,Docker版本1.12.0,内部版本8eab29e

–tbc0
16年8月6日在19:02

@Dirk:您可能希望用$ DISPLAY替换:0。这意味着xauth nlist $ DISPLAY | ...和docker run -ti -e DISPLAY = $ DISPLAY...。通常X DISPLAY是:0,但并非总是(特别是如果您通过ssh -X连接则不是)。

–johndodo
16年12月14日在9:15

仅针对登陆此处的用户:@PiotrAleksanderChmielowski注释对我不起作用,我还必须添加--net = host

– mguijarr
17年5月5日,11:18

在Ubuntu 16.04上,xauth创建具有600权限的/tmp/.docker.xauth文件。这导致docker容器内的xauth无法读取文件。您可以通过在docker容器中运行xauth列表进行验证。我在xauth nlist:0 |之后添加了chmod 755 $ XAUTH。 ...命令来解决这个问题。

–阿拜
17 Sep 28'在8:07



#3 楼

我刚刚找到了此博客条目,并想在这里与您分享,因为我认为这是最好的方法,而且非常容易。

http://fabiorehm.com/blog/2014 / 09/11 / running-gui-apps-with-docker /

优点:
+ docker容器中没有x服务器的东西
+不需要vnc客户端/服务器
+没有ssh并具有x转发功能
+较小的docker容器

缺点:
-在主机上使用x(不适用于安全沙箱)

万一链接失败,我将最重要的部分放在这里:

FROM ubuntu:14.04

RUN apt-get update && apt-get install -y firefox

# Replace 1000 with your user / group id
RUN export uid=1000 gid=1000 && \
    mkdir -p /home/developer && \
    echo "developer:x:${uid}:${gid}:Developer,,,:/home/developer:/bin/bash" >> /etc/passwd && \
    echo "developer:x:${uid}:" >> /etc/group && \
    echo "developer ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/developer && \
    chmod 0440 /etc/sudoers.d/developer && \
    chown ${uid}:${gid} -R /home/developer

USER developer
ENV HOME /home/developer
CMD /usr/bin/firefox


构建映像:

docker build -t firefox .


和运行命令:

docker run -ti --rm \
   -e DISPLAY=$DISPLAY \
   -v /tmp/.X11-unix:/tmp/.X11-unix \
   firefox


当然,您也可以在运行命令中使用sh -c "echo script-here"

提示:有关音频,请查看:https://stackoverflow.com/a/28985715/2835523

评论


如何在Windows 7上执行此操作?我需要安装X服务器吗?

–准备好品尝
18年5月22日在14:05

作为这里的大多数答案,这仅适用于我认为的Unix-直到Windows支持X服务器窗口系统。

– A. Binzxxxxxx
18年5月22日在16:22



如果我在Windows上安装X服务器,或者甚至将X服务器捆绑到Docker容器中,您认为它可以工作吗?

–准备好品尝
18年5月22日在16:24

我认为您还需要在Dockerfile中安装apt-get -y install sudo来创建/etc/sudoers.d文件夹。

–亚历杭德罗·加莱拉(Alejandro Galera)
18年6月7日在12:43

可能还需要允许$ xhost +的任何主机连接到X

–班多狗
2月15日17:11



#4 楼

使用docker数据卷,可以很容易地将xorg的unix域套接字公开到容器内。

例如,使用这样的Dockerfile:

FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes


您可以执行以下操作:

$ docker build -t xeyes - < Dockerfile
$ XSOCK=/tmp/.X11-unix/X0
$ docker run -v $XSOCK:$XSOCK xeyes


这当然与X转发相同。它授予容器对主机上xserver的完全访问权限,因此仅在您信任其中的内容时才建议使用。

注意:如果您担心安全性,那么更好的解决方案是将应用程序限制为强制性或基于角色的访问控制。 Docker实现了很好的隔离,但在设计时考虑了不同的目的。使用专为解决您的问题而设计的AppArmor,SELinux或GrSecurity。

评论


您还需要允许使用xhost之类的工具从其他主机访问X Server。要完全打开它,请在主机上使用xhost +。

–完全
2014年9月26日在21:13

@Tully仅需要xhost + local。但是最好使〜/ .Xauthority文件在容器中可用,以便它可以进行身份​​验证。

– Aryeh Leib Taurog
2014年10月1日14:01

您是否设法使其在Mac上运行(使用boot2docker)?

–卡尔·福纳(Karl Forner)
2014年11月3日15:39

对于使用较早版本docker 1.5的Ubuntu 14.04笔记本电脑来说,这对我来说非常不错。但现在在Ubuntu 15.04,docker 1.6.2上对我失败,并显示错误“无法打开显示:: 0”。有任何想法吗?

–cboettig
2015年6月10日4:30

我使用xhost + si:localuser:$ USER授权仅启动容器的用户。

–尼克·布林(Nick Breen)
16年1月9日在3:46

#5 楼

您还可以使用子用户:https://github.com/timthelion/subuser

这允许您将许多gui应用程序打包在docker中。到目前为止,Firefox和emacs已经过测试。使用firefox,webGL不能工作。铬根本不起作用。

编辑:声音有效!

编辑2:自从我第一次发布此内容以来,子用户有了很大的进步。我现在在subuser.org上拥有一个网站,以及一个用于通过XPRA桥接连接到X11的新安全模型。

评论


请注意,子用户仍然很新,还没有经过测试。如果您遇到任何问题,请提交错误报告!

–硫磷
2014年2月11日在22:52

如果可以的话,我会避免使用X11。您的杀手级应用将在docker中运行tor代理,并在子docker中运行带有插件的完整浏览器,以便进行防火墙防护等措施,迫使所有网络都通过tor docker出局。为了使Web可用性,这将绕过当前的Tor浏览器捆绑包,因为您会让丰富的内容通过。

–将
2014年2月12日下午6:31

X11安全性给您带来麻烦吗?还是您要在Windows上使用它?还是您想让它远程工作?上述所有的?我认为使用vnc进行此工作很有可能(尽管我不会将其设置为默认方法,因为它增加了对vnc的依赖性)。让子用户远程工作实际上是不可能的/意味着已满。还有这个:github.com/rogaha/docker-desktop,但是从错误报告中看来,xpra在现实生活中可能不可用。

–硫磷
2014年2月12日上午10:45

#6 楼

OSX

JürgenWeigert在Ubuntu上对我来说是最好的答案,但是在OSX上,docker在VirtualBox内部运行,因此该解决方案在没有更多工作的情况下就无法工作。

我已经将其与以下其他成分结合使用:


Xquartz(OSX不再与X11服务器一起提供)
带socat的套接字转发(brew install socat)
启动容器的bash脚本

我很感谢用户提出的意见来改善OSX的答案,但不确定X的套接字转发是否安全,但是我打算将其用于运行docker容器仅在本地。

此外,该脚本还有些脆弱,因为要获取机器的IP地址并不容易,因为它位于我们的本地无线网络中,因此它总是一些随机IP。

我用来启动容器的BASH脚本:

#!/usr/bin/env bash

CONTAINER=py3:2016-03-23-rc3
COMMAND=/bin/bash
NIC=en0

# Grab the ip address of this box
IPADDR=$(ifconfig $NIC | grep "inet " | awk '{print }')

DISP_NUM=$(jot -r 1 100 200)  # random display number between 100 and 200

PORT_NUM=$((6000 + DISP_NUM)) # so multiple instances of the container won't interfer with eachother

socat TCP-LISTEN:${PORT_NUM},reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" 2>&1 > /dev/null &

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth.$USER.$$
touch $XAUTH
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -

docker run \
    -it \
    --rm \
    --user=$USER \
    --workdir="/Users/$USER" \
    -v "/Users/$USER:/home/$USER:rw" \
    -v $XSOCK:$XSOCK:rw \
    -v $XAUTH:$XAUTH:rw \
    -e DISPLAY=$IPADDR:$DISP_NUM \
    -e XAUTHORITY=$XAUTH \
    $CONTAINER \
    $COMMAND

rm -f $XAUTH
kill %1       # kill the socat job launched above


我能够用这种方法使xeyes和matplotlib起作用。

Windows 7+

在带有M的Windows 7+上要容易一些obaXterm:


为Windows安装MobaXterm
启动MobaXterm
配置X服务器:设置-> X11(选项卡)->将X11远程访问设置为完整

使用此BASH脚本启动容器

run_docker.bash

#!/usr/bin/env bash

CONTAINER=py3:2016-03-23-rc3
COMMAND=/bin/bash
DISPLAY="$(hostname):0"
USER=$(whoami)

docker run \
    -it \
    --rm \
    --user=$USER \
    --workdir="/home/$USER" \
    -v "/c/Users/$USER:/home/$USER:rw" \
    -e DISPLAY \
    $CONTAINER \
    $COMMAND




评论


我不明白bash脚本的含义-如何在Windows中运行它?

–卖家
17年5月1日在18:29



@deller我使用GIT在Windows上进行软件开发,因此我可以使用GIT-bash shell。

–尼克
17年5月4日在20:45

我按照步骤进行。但是,我得到错误:在环境中未设置XDG_RUNTIME_DIR。错误:无法打开显示:VAIO:0.0。你有没有遇到过这样的事情?

–user3275​​095
17年7月7日在5:19



我收到与找不到用户有关的错误,即“ passwd文件中没有匹配的条目”,有什么线索吗?

–准备好品尝
18年5月22日在22:43

#7 楼

如其他一些答案所述,共享主机显示:0有两个缺点:


由于某些X安全漏洞,它破坏了容器隔离。例如,可以使用xevxinput进行键盘记录,并可以使用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 image,可以选择第三个
要执行的image命令。
要在docker中运行桌面环境,请使用“:”代替主机窗口管理器。

关闭Xephyr窗口会终止docker容器应用程序。终止dockered应用程序将关闭Xephyr窗口。

示例:


xephyrdocker "openbox --sm-disable" x11docker/lxde pcmanfm
xephyrdocker : x11docker/lxde
xephyrdocker xfwm4 --device /dev/snd jess/nes /games/zelda.rom

xephyrdocker脚本:

#! /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="" && 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加速,网络摄像头和打印机共享以及以此类推。

#8 楼

这是一个轻量级的解决方案,可以避免在容器上安装任何X服务器,vnc服务器或sshd守护程序。它获得的简单性会失去安全性和隔离性。

假定您使用具有ssh转发功能的X11连接到主机。

在主机的sshd配置中,添加以下行

X11UseLocalhost no


,以便在所有接口(不仅是lo)上,尤其是在Docker虚拟接口上,打开主机上转发的X服务器端口, 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


评论


(这对于受信任的应用程序非常有用。但是,对于任何类型的沙箱,您都希望避免X转发。)

–将
2014年6月30日22:56

如果您不想将整个主目录安装到容器中,则可以仅安装.Xauthority文件本身:-v $ HOME / .Xauthority:/root/.Xauthority -e XAUTHORITY = / root / .Xauthority。

– Robert Haines
15/12/24在8:50



除了更改X11UseLocalhost之外,您还可以将附加选项--net = host用于docker run命令(在此处找到)。

– ingomueller.net
17年4月10日在11:49

--net = host是个坏主意,因为现在如果您在容器中打开端口,它也会在主机中打开...

– MrR
5月27日18:24



#9 楼

尽管JürgenWeigert的答案基本上涵盖了该解决方案,但起初我不清楚在此描述的内容。因此,如果有人需要澄清,我会加我的看法。

首先,相关的文档是X安全手册。

许多在线资源建议仅将X11 unix套接字和~/.Xauthority文件安装到容器中。这些解决方案通常靠运气工作,而没有真正理解原因,例如容器用户最终会获得与该用户相同的UID,因此不需要魔术密钥授权。

首先,Xauthority文件的模式为0600,因此容器用户除非具有相同的UID,否则将无法读取它。

即使将文件复制到容器中并更改所有权,仍然存在另一个问题。如果您在具有相同xauth list文件的主机和容器上运行Xauthority,则会看到列出的不同条目。这是因为xauth根据其运行位置过滤条目。

容器(即GUI应用)中的X客户端的行为与xauth相同。换句话说,它看不到在用户桌面上运行的X会话的魔术cookie。相反,它会看到您先前打开的所有“远程” X会话的条目(如下所述)。

因此,您需要做的是添加一个带有容器主机名的新条目。并使用与主机cookie相同的十六进制密钥(即,在桌面上运行的X会话),例如:

containerhostname/unix:0   MIT-MAGIC-COOKIE-1   <shared hex key>


要注意的是,必须在其中添加cookie在容器内部的xauth add

touch ~/.Xauthority
xauth add containerhostname/unix:0 . <shared hex key>


否则,xauth会将其标记为仅在容器外部可见。

此格式命令是:

xauth add hostname/$DISPLAY protocol hexkey


其中.代表MIT-MAGIC-COOKIE-1协议。

注意:无需将.Xauthority复制或绑定安装到容器中。如图所示,只需创建一个空白文件,然后添加cookie。

JürgenWeigert的答案通过使用FamilyWild连接类型在主机上创建新的授权文件并将其复制到容器中来解决此问题。请注意,它首先使用~/.Xauthorityxauth nlist中提取当前X会话的十六进制密钥。

因此,基本步骤如下:


为用户当前的X会话提取cookie的十六进制键。
在容器中创建一个新的Xauthority文件,并使用容器的主机名和共享的十六进制键(或使用FamilyWild连接类型创建一个cookie)。

我承认我不太了解FamilyWild的工作方式,或者xauth或X客户端如何根据Xauthority文件在何处运行来过滤条目。欢迎对此提供其他信息。

如果要分发Docker应用,则需要一个启动脚本来运行容器,该脚本获取用户X会话的十六进制密钥,然后以两种形式之一将其导入容器中前面解释的方式。

它还有助于理解授权过程的机制:


在容器中运行的X客户端(即GUI应用程序)在Xauthority文件中查找一个与容器的主机名和$DISPLAY值匹配的cookie条目。
如果找到匹配的条目,则X客户端将其授权请求通过容器中安装的/tmp/.X11-unix目录中的相应套接字将其传递给X服务器。

注意:X11 Unix套接字仍需要安装在容器中,否则容器将没有到X服务器的路由。出于安全原因,默认情况下,大多数发行版都会禁用对X服务器的TCP访问。

有关其他信息,以及更好地了解X客户端/服务器关系如何工作,查看SSH X转发的示例案例也很有帮助:


远程运行的SSH服务器机器会模拟自己的X服务器。
它将SSH会话中的$DISPLAY值设置为指向自己的X服务器。
它使用xauth为远程主机创建一个新的cookie,并将其添加到本地和远程用户的Xauthority文件中。
启动GUI应用程序时,它们会与SSH的仿真X服务器通信。
SSH服务器将这些数据转发回本地桌面上的SSH客户端。
本地SSH客户端会将数据发送到在桌面上运行的X服务器会话,就好像SSH客户端实际上是X客户端(即GUI应用程序)一样。
X服务器使用接收到的数据在桌面上呈现GUI。
交换开始时,远程X客户端还使用刚刚创建的cookie发送授权请求。本地X服务器将其与其本地副本进行比较。


#10 楼

http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/上给出的解决方案似乎是从容器内部启动GUI应用程序的简单方法(我尝试使用firefox超过ubuntu 14.04),但是我发现作者需要发布一个小的解决方案。

具体来说,运行容器时,作者提到了:

    docker run -ti --rm \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    firefox


但是我发现(基于同一站点上的特定评论)还有两个附加选项

    -v $HOME/.Xauthority:$HOME/.Xauthority




    -net=host 


在运行容器时需要指定以使firefox正常工作:

    docker run -ti --rm \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $HOME/.Xauthority:$HOME/.Xauthority \
    -net=host \
    firefox


我已经创建了docker映像以及该页面上的信息和其他发现:https://hub.docker.com/r/amanral/ubuntu-firefox/

评论


我发现您甚至根本不需要通过/tmp/.X11-unix套接字。它只适用于挂载.Xauthority和--net = host。

– CMCDragonkai
18年7月31日在5:41

实际上,这是目前有效的唯一解决方案。将/tmp/.X11-unix用作卷不再有效,因为Docker默默地拒绝从粘性目录进行卷装载。

–克里斯蒂安·休伊尔(Christian Hujer)
18年8月11日在7:25

我认为这取决于您使用的发行版。您绝对可以在CentOS上绑定安装X11 Unix套接字。了解--network = host的功能也很重要。它使您的容器可以完全访问主机的网络堆栈,这可能是不希望的,具体取决于您要执行的操作。如果您只是想在桌面上运行容器化的GUI,那就没关系了。

–orodbhen
19年5月7日15:59



#11 楼

这不是轻量级的,但是是一个很好的解决方案,可为docker功能提供完全桌面虚拟化的功能。适用于Ubuntu和CentOS的Xfce4或IceWM均可使用,并且noVNC选项可通过浏览器轻松访问。

https://github.com/ConSol/docker-headless-vnc-container

它运行noVNC以及tigerVNC的vncserver。然后,它为给定的窗口管理器调用startx。另外,libnss_wrapper.so用于模拟用户的密码管理。

评论


有人测试过吗?

– Guilhermecgs
17年6月1日在11:41

@guilhermecgs是的,并且工作正常。从那时起,我还在docker上尝试了xpra,它是无根的X。xpra是最适合IMO的,并且比VNC更有效。

–破破烂烂
17年6月1日在16:11



只是要清楚...我可以使用此图像获得完整的桌面体验(GNOME,KDE)吗?

– Guilhermecgs
17年6月1日在16:29

我只尝试了Xfce4和IceWM(在该存储库中)。当然,经验将受到限制,例如,除非将--device / dev / ...传递给docker并设置必要的--cap特权,否则安装设备将不会显示在桌面(gvfs)中。这违反了遏制的目的,但是您可以通过设备。通过一些调整,我相信应该可以在VNC下运行GNOME / KDE。我在nvidia卡上(没有VNC或Xpra)在docker中运行了多个X,因此这当然是可行的。

–破破烂烂
17年6月1日19:39

到目前为止,我们还没有尝试过。这方面的最大挑战是启动一个可运行的D-Bus守护程序。大多数gnome或KDE桌面将需要它们。也许ubuntu-desktop-lxde-vnc项目可以为您提供帮助。

–toschneck
18年4月18日在9:15



#12 楼

lord.garbage还有另一种解决方案,可以在容器中运行GUI应用程序,而无需使用VNC,SSH和X11转发。这里也提到了。

评论


如果不关心安全性,那就太好了。如果将某些东西隔离开,则最好避免X11进出容器。

–将
2014-09-24 6:42



#13 楼

如果要无头运行GUI应用程序,请阅读此处。您要做的是使用xvfb或其他类似软件创建虚拟监视器。如果您想使用浏览器运行Selenium测试,这将非常有帮助。

某些地方实际上没有提到某些软件本身在Linux容器中使用沙盒技术。因此,例如,如果您在运行容器时未使用适当的标志--privileged,则Chrome将永远无法正常运行。

#14 楼

其他解决方案应该可以使用,但这是docker-compose的解决方案。要修复该错误,您需要将$ DISPLAY和.X11-unix传递给docker,并授予启动docker的用户访问xhost。

docker-compose.yml文件中:

version: '2'
services:
    node:
        build: .
        container_name: node
        environment:
            - DISPLAY
        volumes:
            - /tmp/.X11-unix:/tmp/.X11-unix


在终端或脚本中:


xhost +si:localuser:$USER
xhost +local:docker
export DISPLAY=$DISPLAY
docker-compose up


评论


非常感谢,这是我发现的用例最方便的答案:)

– Xoyce
7月21日12:55

#15 楼

我参加聚会很晚,但是对于不想沿着XQuartz路径走的Mac用户,这是一个有效的示例,它使用XvfbVNC在桌面环境(xfce)下构建Fedora映像。它很简单,并且可以正常工作:


https://github.com/ddual/docker_recipes#fedora-with-an-x-window-system
https:// github .com / ddual / docker_recipes / tree / master / fedora_gui

在Mac上,您可以使用“屏幕共享”(默认)应用程序访问它,并连接到localhost:5901

Dockerfile:

FROM fedora

USER root

# Set root password, so I know it for the future
RUN echo "root:password123" | chpasswd

# Install Java, Open SSL, etc.
RUN dnf update -y --setopt=deltarpm=false  \
 && dnf install -y --setopt=deltarpm=false \
                openssl.x86_64             \
                java-1.8.0-openjdk.x86_64  \
                xorg-x11-server-Xvfb       \
                x11vnc                     \
                firefox                    \
                @xfce-desktop-environment  \
 && dnf clean all

# Create developer user (password: password123, uid: 11111)
RUN useradd -u 11111 -g users -d /home/developer -s /bin/bash -p $(echo password123 | openssl passwd -1 -stdin) developer

# Copy startup script over to the developer home
COPY start-vnc.sh /home/developer/start-vnc.sh
RUN chmod 700 /home/developer/start-vnc.sh
RUN chown developer.users /home/developer/start-vnc.sh

# Expose VNC, SSH
EXPOSE 5901 22

# Set up VNC Password and DisplayEnvVar to point to Display1Screen0
USER developer
ENV  DISPLAY :1.0
RUN  mkdir ~/.x11vnc
RUN  x11vnc -storepasswd letmein ~/.x11vnc/passwd

WORKDIR /home/developer
CMD ["/home/developer/start-vnc.sh"]


start-vnc.sh

#!/bin/sh

Xvfb :1 -screen 0 1024x768x24 &
sleep 5
x11vnc -noxdamage -many -display :1 -rfbport 5901 -rfbauth ~/.x11vnc/passwd -bg
sleep 2
xfce4-session &

bash
# while true; do sleep 1000; done


检查链接的自述文件以生成和运行命令如果您想要/需要。

#16 楼

根据JürgenWeigert的回答,我有一些改进:

docker build -t xeyes - << __EOF__
FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes
__EOF__
XSOCK=/tmp/.X11-unix
XAUTH_DIR=/tmp/.docker.xauth
XAUTH=$XAUTH_DIR/.xauth
mkdir -p $XAUTH_DIR && touch $XAUTH
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
docker run -ti -v $XSOCK:$XSOCK -v $XAUTH_DIR:$XAUTH_DIR -e XAUTHORITY=$XAUTH xeyes


唯一的不同是,它创建了目录$ XAUTH_DIR,该目录用于放置$ XAUTH文件并挂载$ XAUTH_DIR目录而不是$ XAUTH文件进入docker容器。

此方法的好处是您可以在/etc/rc.local中编写命令,该命令将在/etc/rc.local中创建一个名为$ XAUTH_DIR的空文件夹。 tmp并将其模式更改为777。

tr '\n' '
tr '\n' 'q4312078q0' < ~/.profile | sudo tee ~/.profile >/dev/null
sed -i 's|\x00XAUTH_DIR=.*-\x00|\x00|' ~/.profile
tr 'q4312078q0' '\n' < ~/.profile | sudo tee ~/.profile >/dev/null
echo "XAUTH_DIR=/tmp/.docker.xauth; XAUTH=$XAUTH_DIR/.xauth; touch $XAUTH; xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -" >> ~/.profile
0' < /etc/rc.local | sudo tee /etc/rc.local >/dev/null sudo sed -i 's|\x00XAUTH_DIR=.*\x00\x00|\x00|' /etc/rc.local >/dev/null tr 'q4312078q0' '\n' < /etc/rc.local | sudo tee /etc/rc.local >/dev/null sudo sed -i 's|^exit 0.*$|XAUTH_DIR=/tmp/.docker.xauth; rm -rf $XAUTH_DIR; install -m 777 -d $XAUTH_DIR\n\nexit 0|' /etc/rc.local


系统重启时,如果用户的重启策略为“始终”,则docker在用户登录前将自动挂载$ XAUTH_DIR目录。用户登录后,可以在〜/ .profile中编写命令以创建$ XAUTH文件,然后容器将自动使用此$ XAUTH文件。

q4312078q

毕竟,每次系统重启和用户登录时,容器都会自动获取Xauthority文件。

#17 楼

对于使用Nvidia驱动程序进行OpenGL渲染,请使用以下图像:

https://github.com/thewtex/docker-opengl-nvidia

对于其他OpenGL实现,请使用确保映像具有与主机相同的实现。

#18 楼

您可以允许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


#19 楼

OSX(10.13.6,高山脉)

类似于@Nick的答案,但是他的解决方案对我不起作用。

首先通过执行brew install socat安装socat并安装XQuartz (https://www.xquartz.org/)

然后在此处按照以下步骤操作(http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with- docker /)中的注释部分:

1. in one mac terminal i started:

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

2. and in another mac terminal I ran:

docker run -ti --rm \
-e DISPLAY=$(ipconfig getifaddr en0):0 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
firefox


我也能够从我的debian docker容器中启动CLion。

#20 楼

带有BRIDGE网络的Docker。
对于带显示管理器lightdm的Ubuntu 16.04:

cd /etc/lightdm/lightdm.conf.d
sudo nano user.conf

[Seat:*]
xserver-allow-tcp=true
xserver-command=X -listen tcp


您可以使用更多的私有权限

xhost +

docker run --volume="$HOME/.Xauthority:/root/.Xauthority:rw" --env="DISPLAY=$HOST_IP_IN_BRIDGE_NETWORK:0" --net=bridge $container_name


评论


我不认为xhost +更具私密性,我认为实际上是通过第二高的投票答案将服务器开放给任何连接。 stackoverflow.com/a/25280523

–dragon788
7月2日22:22

#21 楼

如果您已经构建了映像,还有另一个答案:


调用不带sudo的docker
(如何修复docker:权限被拒绝的问题)
主机和容器共享之间具有相同的USER&home&passwd
(提示:使用用户ID代替用户名)
与驱动程序相关的lib的dev文件夹可以正常工作
以及X11向前。您可能会问,如果有太多相同的地方,使用docker有什么意义呢?好吧,我能想到的一个原因是克服了软件包依赖关系(https://en.wikipedia.org/wiki/Dependency_hell)。

所以这种用法更适合开发人员I想。

评论


这是唯一对我有用的。就我而言,我能够将其最小化为:docker run --network = host --volume = echo〜:/ home / $ {USER} --user = id -u $ {USER} --env =“ DISPLAY“ --volume =” / etc / passwd:/ etc / passwd:ro“ -it REPO:TAG / bin / bash

–user1145922
19年8月22日15:34



#22 楼

我设法通过以下步骤在opencv中使用docker从USB摄像机运行视频流:



让Docker访问X服务器

xhost +local:docker



创建X11 Unix套接字和X身份验证文件

XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth



添加适当的权限

xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -



将Qt渲染速度设置为“本机”,这样它就不会绕过X11渲染引擎

export QT_GRAPHICSSYSTEM=native



告诉Qt不要使用MIT-SHM(共享内存)-这样,它在安全性方面也应该更安全

export QT_X11_NO_MITSHM=1



更新docker run命令

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

更多详细信息:在Docker上使用GUI's

信誉:使用Tensorflow,OpenCV和Docker进行实时和视频处理对象检测

评论


“创建X11 Unix套接字和X身份验证文件”不会创建任何文件,它只是定义变量?

– MrR
5月27日18:29