你可以在Docker容器中运行GUI应用程序吗?

时间:2013-04-30 09:40:54

标签: x11 sandbox docker vnc

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

是否有任何图片可以设置vncserver或其他类似的东西 - 例如 - 在Firefox周围添加额外的speedbump沙盒?

21 个答案:

答案 0 :(得分:220)

您只需安装vncserver和Firefox:)

我在这里推了一个图像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的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

答案 1 :(得分:180)

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

可以以某种方式编写Xauthority文件,以便主机名无关紧要。 我们需要将Authentication Family设置为'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

答案 2 :(得分:59)

我刚刚找到了这篇博客文章,并希望与您分享,因为我认为这是最好的方式,而且非常简单。

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

PROS:
+在docker容器中没有x服务器东西
+不需要vnc客户端/服务器
+没有ssh与x转发
+小得多的码头集装箱

CONS:
- 在主机上使用x(不适用于安全沙盒)

如果有一天链接失败,我会把最重要的部分放在这里:
dockerfile:

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

答案 3 :(得分:49)

使用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-forwarding相同。它授予容器对主机上xserver的完全访问权限,因此只有在您信任其中的内容时才建议使用它。

注意:如果您担心安全问题,更好的解决方案是将应用限制为mandatory-role-based-访问控制。 Docker实现了相当好的隔离,但它的设计考虑了不同的目的。使用旨在解决您问题的AppArmorSELinuxGrSecurity

答案 4 :(得分:26)

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

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

编辑:声音有效!

EDIT2:自我第一次发布此内容以来,子用户已经取得了很大进展。我现在有一个网站subuser.org,以及一个用于连接到X11 via XPRA bridging的新安全模型。

答案 5 :(得分:23)

OSX

Jürgen Weigert在Ubuntu上有最适合我的答案,但是在OSX上,docker在VirtualBox内部运行,因此如果没有更多的工作,解决方案就无法工作。

我已经使用了这些额外的成分:

  1. Xquartz(OSX不再附带X11服务器)
  2. 使用socat进行套接字转发(brew install socat)
  3. 用于启动容器的bash脚本
  4. 我很感激用户评论来改进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 $2}')
    
    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 +

    使用MobaXterm在Windows 7+上更容易一些:

    1. 安装MobaXterm for windows
    2. 启动MobaXterm
    3. 配置X服务器:设置 - &gt; X11 (标签) - &gt;将 X11远程访问设置为完整
    4. 使用此BASH脚本启动容器
    5. 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
      

      xeyes running on PC

答案 6 :(得分:18)

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

它假定您使用带有ssh转发的X11连接到主机。

在主机的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

答案 7 :(得分:16)

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

  • 由于一些X安全漏洞,它打破了容器隔离。例如,可以使用xevxinput进行键盘记录,并使用xdotool远程控制主机应用程序。
  • 由于缺少X扩展MIT-SHM的共享内存,应用程序可能会出现渲染故障和错误的RAM访问错误。 (也可以使用隔离降级选项--ipc=host修复)。

在Xephyr中运行docker镜像的示例脚本下面解决了这个问题。

  • 它避免了X安全漏洞,因为docker应用程序在嵌套的X服务器中运行。
  • 禁用MIT-SHM以避免RAM访问失败。
  • 使用--cap-drop ALL --security-opt no-new-privileges改进了容器安全性。容器用户也是 root。
  • 创建一个X cookie以限制对Xephyr显示的访问。

脚本需要一些参数,首先是在Xephyr中运行的主机窗口管理器,第二个是docker镜像,可选择第三个 要执行的图像命令。 要在docker中运行桌面环境,请使用“:”而不是主机窗口管理器。

关闭Xephyr窗口会终止docker容器应用程序。终止停靠的应用程序会关闭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="$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加速,网络摄像头和打印机共享等功能。

答案 8 :(得分:11)

这不是轻量级的,但它是一个很好的解决方案,可以让docker功能与完整的桌面虚拟化保持一致。用于Ubuntu和CentOS的Xfce4或IceWM都可以工作,而noVNC选项可以通过浏览器轻松访问。

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

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

答案 9 :(得分:10)

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

首先,相关文档是X security manpage

众多在线资源建议仅将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>

要注意的是,必须在容器内添加xauth add来添加cookie:

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

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

此命令的格式为:

xauth add hostname/$DISPLAY protocol hexkey

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

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

Jürgen Weigert的答案是通过使用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 :(得分:9)

http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/给出的解决方案似乎确实是一种从容器内部启动GUI应用程序的简单方法(我在ubuntu 14.04上尝试过firefox)但我发现需要对发布的解决方案进行一些额外的更改作者。

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

O(n^2)

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

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

    -v $HOME/.Xauthority:$HOME/.Xauthority
运行容器时需要指定

以使firefox正常工作:

    -net=host 

我创建了一个包含该页面信息的docker镜像以及这些额外的发现:https://hub.docker.com/r/amanral/ubuntu-firefox/

答案 11 :(得分:7)

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

在任何地方都没有提到的是某些软件实际上自己使用沙盒与Linux容器。因此,例如,如果在运行容器时未使用相应的标记--privileged,则Chrome将永远无法正常运行。

答案 12 :(得分:6)

在不使用VNC,SSH和X11转发的容器中运行GUI应用程序another solution by lord.garbage。它也被提到here

答案 13 :(得分:5)

我迟到了,但对于那些不想沿着XQuartz路径前进的Mac用户,这里有一个使用{{1}构建Fedora映像的桌面环境(xfce)的工作示例}和Xvfb。这很简单,也很有效:

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

Dockerfile:

localhost:5901

start-vnc.sh

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"]

如果您需要/需要,请检查链接的readme是否有构建和运行命令。

答案 14 :(得分:5)

根据Jürgen Weigert的答案,我有一些改进:

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中编写一个命令,即在/ tmp中创建一个名为$ XAUTH_DIR的空文件夹,并将其模式更改为777.

tr '\n' '\000' < /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 '\000' '\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

当系统重新启动时,在用户登录之前,如果容器的重启策略是&#34;总是&#34;,则docker将自动挂载$ XAUTH_DIR目录。用户登录后,可以在〜/ .profile中编写一个命令来创建$ XAUTH文件,然后容器会自动使用这个$ XAUTH文件。

tr '\n' '\000' < ~/.profile | sudo tee ~/.profile >/dev/null
sed -i 's|\x00XAUTH_DIR=.*-\x00|\x00|' ~/.profile
tr '\000' '\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

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

答案 15 :(得分:3)

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

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

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

答案 16 :(得分:3)

其他解决方案应该有效,但这是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

答案 17 :(得分:2)

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

答案 18 :(得分:1)

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。

答案 19 :(得分:1)

具有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

答案 20 :(得分:0)

如果您已经构建了图像,请再回答一个问题:

  1. 不使用sudo调用docker (How to fix docker: Got permission denied issue

  2. 在主机和容器共享之间共享相同的USER&home&passwd (提示:使用用户ID代替用户名)

  3. 依赖于驱动程序的lib的dev文件夹可以正常工作

  4. 再加上X11。

    docker run --name=CONTAINER_NAME --network=host --privileged \
      -v /dev:/dev \
      -v `echo ~`:/home/${USER} \
      -p 8080:80 \
      --user=`id -u ${USER}` \
      --env="DISPLAY" \
      --volume="/etc/group:/etc/group:ro" \
      --volume="/etc/passwd:/etc/passwd:ro" \
      --volume="/etc/shadow:/etc/shadow:ro" \
      --volume="/etc/sudoers.d:/etc/sudoers.d:ro" \
      --volume="/tmp/.X11-unix:/tmp/.X11-unix:rw" \
      -it REPO:TAG /bin/bash

您可能会问,如果有太多相同的东西,那么使用docker有什么意义呢?好吧,我能想到的一个原因是克服了软件包依赖度(https://en.wikipedia.org/wiki/Dependency_hell)。

所以我认为这种用法更适合开发人员。