478

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

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

4

24 回答 24

275

您可以简单地安装 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
于 2013-05-01T00:55:28.217 回答
211

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
于 2014-08-13T07:33:45.077 回答
82

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

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

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

缺点:
- 在主机上使用 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

于 2015-03-10T18:28:44.453 回答
58

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

注意:如果您担心安全性,更好的解决方案是使用强制基于角色的访问控制来限制应用程序。Docker 实现了很好的隔离,但它的设计目的不同。使用专为解决您的问题而设计的AppArmorSELinuxGrSecurity 。

于 2014-08-06T19:21:28.127 回答
27

操作系统

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

我已经让它与这些额外的成分一起工作:

  1. Xquartz(OSX 不再附带 X11 服务器)
  2. 使用 socat 进行套接字转发(brew install socat)
  3. 启动容器的 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 使用这种方法。

视窗 7+

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

  1. 为 windows 安装 MobaXterm
  2. 启动 MobaXterm
  3. 配置 X 服务器:设置-> X11(选项卡) -> 将X11 远程访问设置为完全
  4. 使用此 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 在 PC 上运行

于 2016-03-23T23:12:23.970 回答
26

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

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

编辑:声音有效!

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

于 2014-02-11T22:49:17.730 回答
24

如其他一些答案所述,共享主机显示: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 映像,第三个是可选的要执行的映像命令。要在 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="$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 加速、网络摄像头和打印机共享等功能。

于 2016-09-24T21:13:22.173 回答
19

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

ssh它假设您使用with X11forwarding连接到主机。

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
于 2014-06-30T19:51:13.063 回答
17

虽然Jürgen Weigert的回答基本上涵盖了这个解决方案,但起初我并不清楚那里描述的是什么。所以我会添加我的看法,以防其他人需要澄清。

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

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

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

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

容器中的 X 客户端(即 GUI 应用程序)的行为与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

where.代表MIT-MAGIC-COOKIE-1协议。

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

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

所以基本的步骤是:

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

我承认我不太了解如何FamilyWild工作,xauth或者 X 客户端如何根据运行位置从 Xauthority 文件中过滤条目。欢迎提供更多信息。

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

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

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

注意: X11 Unix socket 仍然需要挂载在容器中,否则容器将没有到 X 服务器的路由。出于安全原因,大多数发行版默认禁用对 X 服务器的 TCP 访问。

如需更多信息,并更好地掌握 X 客户端/服务器关系的工作原理,查看 SSH X 转发的示例也很有帮助:

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

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

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

它和's vncservernoVNC一样运行。tigerVNC然后它调用startx给定的窗口管理器。此外,libnss_wrapper.so用于模拟用户的密码管理。

于 2017-03-29T01:00:40.307 回答
13

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/

于 2017-09-13T14:53:55.047 回答
9

其他解决方案应该可以工作,但这里有一个解决方案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
于 2018-05-15T17:51:11.923 回答
7

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

任何地方都没有提到的是,一些软件本身实际上使用了 Linux 容器的沙盒。--privileged因此,例如,如果您在运行容器时不使用适当的标志,Chrome 将永远不会正常运行。

于 2014-10-18T09:23:06.847 回答
6

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

于 2014-09-23T13:59:06.733 回答
6

我迟到了,但是对于不想走 XQuartz 路径的 Mac 用户,这里有一个工作示例,它使用XvfbVNC. 这很简单,并且有效:

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

启动-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

如果需要/需要,请检查链接的自述文件以获取构建和运行命令。

于 2017-05-11T14:33:46.027 回答
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

系统重启时,如果容器的重启策略为“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 文件。

于 2017-11-11T12:39:10.260 回答
4

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

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

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

于 2014-08-21T04:29:12.110 回答
4

我设法通过以下步骤使用opencvin运行来自 USB 摄像头的视频流:docker

  1. 让 docker 访问 X 服务器

    xhost +local:docker
    
  2. 创建 X11 Unix 套接字和 X 身份验证文件

    XSOCK=/tmp/.X11-unix
    XAUTH=/tmp/.docker.xauth
    
  3. 添加适当的权限

    xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
    
  4. 将 Qt 渲染速度设置为“native”,这样就不会绕过 X11 渲染引擎

    export QT_GRAPHICSSYSTEM=native
    
  5. 告诉 Qt 不要使用 MIT-SHM(共享内存)——这样在安全方面也应该更安全

    export QT_X11_NO_MITSHM=1
    
  6. 更新 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

学分:使用 Tensorflow、OpenCV 和 Docker 进行实时和视频处理对象检测

于 2019-10-31T15:58:18.563 回答
3

您可以允许 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
于 2016-08-11T10:00:57.187 回答
2

OSX(10.13.6,高山脉)

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

首先通过do安装socat brew install 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。

于 2018-07-27T23:44:31.723 回答
2

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

  1. 调用 docker w/o sudo(如何修复 docker: Got permission denied 问题

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

  3. 驱动程序依赖库的 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)。

所以这种用法我觉得更适合开发者。

于 2019-03-28T02:36:31.447 回答
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
于 2018-11-20T11:16:48.537 回答
0

关于如何将 docker 容器中的 GUI 应用程序连接到主机上运行的 X 服务器,或者如何运行虚拟 X 服务器并使用 VNC 连接到容器来访问它,这里有很多很好的答案。

然而,还有另一种解决方案(这对于信息亭或家庭影院来说非常有用) - 您可以在 docker 容器内运行 X 服务器,并将视频输出到连接到主机的监视器。

首先让我们创建一个 docker 卷来存储 X11 套接字:

docker volume create --name xsocket

现在我们可以使用 X Server 创建一个图像:

FROM ubuntu

RUN apt-get update && \
    DEBIAN_FRONTEND='noninteractive' apt-get install -y xorg

CMD /usr/bin/X :0 -nolisten tcp vt1

让我们构建并启动它并将 X11 套接字存储在xsocketdocker 卷中:

docker build . -t docker-x-server:latest
docker run --privileged -v xsocket:/tmp/.X11-unix -d docker-x-server:latest

现在我们可以在另一个 docker 容器中运行一个 GUI 应用程序(耶!)并使用xsocket卷将它指向我们的 X 服务器:

docker run --rm -it -e DISPLAY=:0 -v xsocket:/tmp/.X11-unix:ro stefanscherer/xeyes

如果您需要输入(如键盘)安装xserver-xorg-input-evdev包并添加-v /run/udev/data:/run/udev/data,因为默认情况下容器中没有udev

--privileged您甚至可以通过授予SYS_TTY_CONFIG功能并将某些设备绑定到容器中来摆脱标志:

docker run --name docker-x-server --device=/dev/input --device=/dev/console --device=/dev/dri --device=/dev/fb0 --device=/dev/tty --device=/dev/tty1 --device=/dev/vga_arbiter --device=/dev/snd  --device=/dev/psaux --cap-add=SYS_TTY_CONFIG  -v xsocket:/tmp/.X11-unix  -d  docker-x-server:latest
于 2021-09-08T23:28:32.733 回答
0

fcwu/docker-ubuntu-vnc-desktop(Ubuntu 18.04、20.04)

https://github.com/fcwu/docker-ubuntu-vnc-desktop提供了方便的设置。该设置并未最小化。最好将其最小化。但我只是没有时间,而且我每次尝试时都会使用它,所以我倾向于使用它。从好的方面来说,因为它没有被最小化,它往往会测试更复杂的程序,你可能会发现它们实际上正在克服 Docker 的无数陷阱。此外,由于每次来宾/主机更新时设置都会中断,因此最小化可以说只能在有限的时间内起作用,直到您不得不再次重新最小化该项目。

要启动它,只需运行:

sudo docker run --name ubvnc -p 6080:80 -p 5900:5900 dorowu/ubuntu-desktop-lxde-vnc:focal

然后在主机上:

在此处输入图像描述

docker要退出,只需在终端上杀死。并重新启动机器:

sudo docker start ubvnc

然后重新连接VNC。然后退出机器:

sudo docker stop ubvnc

您必须等待几秒钟才能启动来宾上的 VNC 服务器,然后才能连接。

客人体内的铬不会从菜单开始。如果您尝试从命令行启动它,它会解释原因:

Running as root without --no-sandbox is not supported. See https://crbug.com/638180.

所以只需从 CLI 运行它:

chromium-browser --no-sandbox

然而,Firefox 不在乎。

TODO:没有音频。--device /dev/snd没有帮助:

编辑:他们为它添加了一个部分:https ://github.com/fcwu/docker-ubuntu-vnc-desktop/tree/e4922ce92f945fc482994b7a0fd95ca5de7295b3#sound-preview-version-and-linux-only

也可以看看:

测试:

  • Ubuntu 19.04 主机,fcwu/docker-ubuntu-vnc-desktop镜像dorowu/ubuntu-desktop-lxde-vncID:70516b87e92d。
  • Ubuntu 21.10 主机,dorowu/ubuntu-desktop-lxde-vnc:focal(Ubuntu 20.04)
于 2022-02-25T11:17:12.873 回答