首页 文章

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

提问于
浏览
318

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

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

20 回答

  • 56

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

  • 2

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

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

  • 20

    你可以简单地安装一个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 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
    
  • 6

    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
    
  • 17

    我刚刚找到了这篇博客文章,想在这里与大家分享,因为我觉得这是最好的方式,而且很容易 .

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

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

    缺点:

    • 在主机上使用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
    

    Build 图像:

    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

    使用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的完全访问权限,因此只有在您信任其中的内容时才建议使用它 .

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

  • 5

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

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

    编辑:声音工作!

    编辑2:自从我第一次发布这篇文章以来,子用户已经取得了很大的进步 . 我现在有一个subuser.org的网站,以及一个用于连接到X11 via XPRA bridging的新安全模型 .

  • 5

    OSX

    Jürgen Weigert具有在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 $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上更容易一些:

    • 为Windows安装MobaXterm

    • 启动MobaXterm

    • 配置X服务器: Settings - > X11 (tab) - >设置 X11 Remote Accessfull

    • 使用此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
    

    xeyes running on PC

  • 1

    这是一个轻量级的解决方案,可以避免在容器上安装任何 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
    
  • 24

    共享主机显示: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镜像,可选地是第三个要执行的image命令 . 要在docker中运行桌面环境,请使用“:”而不是主机窗口管理器 .

    关闭Xephyr窗口会终止docker容器应用程序 . 终止停靠应用程序将关闭Xephyr窗口 .

    Examples:

    • xephyrdocker "openbox --sm-disable" x11docker/lxde pcmanfm

    • 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加速,网络摄像头和打印机共享等功能 .

  • 1

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

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

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

  • 10

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

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

    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/

  • 166

    根据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
    

    系统重启时,在用户登录之前,如果容器的重启策略为“always”,则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
    

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

  • 6

    尽管Jürgen Weigert的回答基本上涵盖了这个解决方案,但是如果其他人需要澄清的话,那就不会加以我的看法 .

    首先,相关文档是X security manpage .

    许多在线消息来源建议只需将X11 unix套接字和 ~/.Xauthority 文件安装到容器中即可 . 这些解决方案通常可以运气,但不能真正理解为什么,例如容器用户最终使用与用户相同的UID,因此不需要魔术密钥授权 .

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

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

    容器中的X客户端(即GUI应用程序)的行为与 xauth 相同 . 换句话说,它不是桌面 . 相反,它会看到您之前打开的所有"remote" 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 协议 .

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

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

    所以必要的步骤是:

    • 为用户当前的X会话提取cookie的十六进制密钥 .

    • 使用容器主机名和共享十六进制密钥在容器中创建一个新的Xauthority文件(或创建一个具有 FamilyWild 连接类型的cookie) .

    我承认我不太了解 FamilyWild 如何工作,或者 xauth 或X客户端如何从Xauthority文件中过滤条目,具体取决于它们的运行位置 . 欢迎提供更多相关信息 .

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

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

    • 在容器中运行的X客户端(即GUI应用程序)在Xauthority文件中查找与容器的主机名和 $DISPLAY 的值匹配的cookie条目 .

    • 如果找到匹配的条目,X客户端将通过其授权请求将其传递给X服务器,通过容器中安装的 /tmp/.X11-unix 目录中的相应套接字 .

    Note: 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服务器将其与本地副本进行比较 .

  • 1

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

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

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

  • 49

    我想要沿着XQuartz路径走下去,这是一个使用 XvfbVNC 构建Fedora映像的桌面环境(xfce)的工作示例 . 它很简单,有效:

    在Mac上,您只需使用 Screen Sharing (默认)应用程序访问它,连接到 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
    

    如果需要/需要,请检查链接的readme以获取构建和运行命令 .

  • 11

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

  • 196

    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 .

  • 8

    Docker与BRIDGE网络 . 对于带有显示管理器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
    

相关问题