如何在Docker容器中运行GUI应用程序?
是否设置了任何图像vncserver
或其他东西,例如,可以在Firefox周围添加一个额外的speedbump沙箱?
如何在Docker容器中运行GUI应用程序?
是否设置了任何图像vncserver
或其他东西,例如,可以在Firefox周围添加一个额外的speedbump沙箱?
Answers:
您可以简单地与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的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
docker inspect <container id>
或简单地docker ps
,那么你与端口连接到主机的ip你刚刚发现。
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
:0
为$DISPLAY
。这意味着xauth nlist $DISPLAY | ...
和docker run -ti -e DISPLAY=$DISPLAY ...
。通常X DISPLAY是:0
,但并非总是(特别是如果您通过ssh -X连接时则不是)。
/tmp/.docker.xauth
具有600
权限的文件。这导致docker容器内的xauth无法读取文件。您可以通过运行来验证xauth list
在docker容器中。我已chmod 755 $XAUTH
在xauth nlist :0 | ...
命令后添加以解决此问题。
我刚刚找到了此博客条目,并想在这里与您分享,因为我认为这是最好的方法,而且非常容易。
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
当然,您也可以在run命令中使用 sh -c "echo script-here"
提示:有关音频,请查看:https : //stackoverflow.com/a/28985715/2835523
apt-get -y install sudo
以创建/etc/sudoers.d
文件夹。
$ xhost +
使用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 +
在主机上使用。
xhost +local
是必需的。最好使~/.Xauthority
文件在容器中可用,以便它可以进行身份验证。
Can't open display: :0
。有任何想法吗?
xhost +si:localuser:$USER
只授权启动容器的用户。
您还可以使用子用户:https : //github.com/timthelion/subuser
这使您可以将许多gui应用程序打包在docker中。到目前为止,Firefox和emacs已经过测试。使用firefox,webGL不能正常工作。铬根本不起作用。
编辑:声音有效!
EDIT2:自从我第一次发布此内容以来,子用户有了很大的进步。我现在在subuser.org上拥有一个网站,以及一个用于通过XPRA桥接连接到X11的新安全模型。
JürgenWeigert在Ubuntu上为我提供了最好的答案,但是在OSX上,docker在VirtualBox内运行,因此该解决方案在没有更多工作的情况下无法工作。
我已经使用了以下其他成分:
我希望用户提出意见以改善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会容易一些:
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
error: XDG_RUNTIME_DIR not set in the environment.
和Error: cannot open display: VAIO:0.0
。你有没有遇到过这样的事情?
如其他答案所述,共享主机显示:0有两个缺点:
xev
或进行键盘记录xinput
,并使用来远程控制主机应用程序xdotool
。--ipc=host
)。下面的示例脚本在Xephyr中运行可解决此问题的docker映像。
--cap-drop ALL --security-opt no-new-privileges
。此外,容器用户不是 root用户。该脚本需要一些参数,首先是宿主窗口管理器在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加速,网络摄像头和打印机共享等功能。
这是一个轻量级的解决方案,可以避免在容器上安装任何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
.Xauthority
文件本身:-v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority
。
--net=host
这是一个坏主意,因为现在如果您在容器中打开端口,它也会在主机中打开...
虽然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>
要注意的是,必须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ürgenWeigert的答案通过使用FamilyWild
连接类型在主机上创建新的授权文件并将其复制到容器中来解决此问题。请注意,它首先~/.Xauthority
使用从中提取当前X会话的十六进制密钥xauth nlist
。
因此,基本步骤是:
FamilyWild
连接类型创建一个cookie )。我承认我不太了解它是如何FamilyWild
工作的,xauth
或者X客户端如何根据运行位置从Xauthority文件中过滤条目。欢迎对此提供其他信息。
如果要分发Docker应用程序,则需要一个启动脚本来运行容器,该脚本获取用户X会话的十六进制密钥,并以前面介绍的两种方式之一将其导入容器。
它还有助于了解授权过程的机制:
$DISPLAY
。/tmp/.X11-unix
容器中安装的目录中的相应套接字,将其及其授权请求传递给X服务器。注意: X11 Unix套接字仍然需要安装在容器中,否则容器将没有到X服务器的路由。出于安全原因,默认情况下,大多数发行版都会禁用对X服务器的TCP访问。
有关其他信息,以及为了更好地了解X客户端/服务器关系的工作方式,研究SSH X转发的示例案例也很有帮助:
$DISPLAY
SSH会话中的值设置为指向自己的X服务器。xauth
用于为远程主机创建一个新的cookie,并将其添加到Xauthority
本地和远程用户的文件中。这不是轻量级的,但是是一个很好的解决方案,可为docker功能提供完全桌面虚拟化的功能。适用于Ubuntu和CentOS的Xfce4或IceWM noVNC
均可使用,并且该选项使您可以通过浏览器轻松访问。
https://github.com/ConSol/docker-headless-vnc-container
它noVNC
与tigerVNC
的vncserver 一样运行。然后,它要求startx
给定的窗口管理器。另外,libnss_wrapper.so
用于模拟用户的密码管理。
xpra
docker中尝试了,它是无根X。xpra
最适合IMO,并且比VNC更有效。
--device /dev/...
给docker并设置必要的--cap
特权,否则安装设备将不会显示在桌面(gvfs)中。这违反了遏制的目的,但是您可以通过设备。通过一些调整,我相信应该可以在VNC下运行GNOME / KDE。我在nvidia卡上(没有VNC或Xpra)在docker中运行了多个X,因此这当然是可行的。
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
。
/tmp/.X11-unix
由于docker默默地拒绝了来自粘性目录的卷挂载,因此无法将其用作卷。
--network=host
。它使您的容器可以完全访问主机的网络堆栈,这可能是不希望的,具体取决于您要执行的操作。如果您只是想在桌面上运行正在运行的容器化GUI,那就没关系了。
我参加聚会很晚,但是对于不想沿着XQuartz路径走的Mac用户,这是一个有效的示例,该示例使用Xvfb
和来通过桌面环境(xfce)构建Fedora映像VNC
。这很简单,并且可以工作:
在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
如果需要,请检查链接的自述文件以构建和运行命令。
根据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中编写命令,该命令将在/ 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
系统重新启动时,如果容器的重新启动策略为“始终”,则在用户登录之前,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文件。
其他解决方案应该可以使用,但这是的解决方案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
对于使用Nvidia驱动程序进行的OpenGL渲染,请使用以下图像:
https://github.com/thewtex/docker-opengl-nvidia
对于其他OpenGL实现,请确保映像具有与主机相同的实现。
类似于@Nick的答案,但他的解决方案对我不起作用。
首先通过安装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。
带有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
如果您已经构建了映像,则还有另一个答案:
不使用sudo调用docker(如何修复docker:权限被拒绝的问题)
在主机和容器共享之间共享相同的USER&home&passwd(提示:使用用户ID代替用户名)
依赖于驱动程序的lib的dev文件夹可以正常工作
再加上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)。
因此,我认为这种用法更适合开发人员。
echo ~
:docker run --network = host --volume = :/ home / $ {USER} --user = id -u ${USER}
--env =“ DISPLAY” --volume =“ / etc / passwd:/ etc / passwd:ro“
我设法运行从使用USB摄像头的视频流opencv
中docker
通过以下步骤:
让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