¿Cómo puede ejecutar aplicaciones GUI en un contenedor Docker ?
¿Hay alguna imagen que se configure vncserver
o algo así para que pueda, por ejemplo, agregar un entorno limitado adicional de speedbump, por ejemplo, Firefox?
¿Cómo puede ejecutar aplicaciones GUI en un contenedor Docker ?
¿Hay alguna imagen que se configure vncserver
o algo así para que pueda, por ejemplo, agregar un entorno limitado adicional de speedbump, por ejemplo, Firefox?
Respuestas:
Simplemente puede instalar un servidor vncs junto con Firefox :)
Empujé una imagen, vnc / firefox, aquí: docker pull creack/firefox-vnc
La imagen se ha hecho con este 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'
Esto creará un contenedor Docker que ejecute VNC con la contraseña 1234
:
Para Docker versión 18 o posterior:
docker run -p 5900:5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create
Para Docker versión 1.3 o posterior:
docker run -p 5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create
Para Docker antes de la versión 1.3:
docker run -p 5900 creack/firefox-vnc x11vnc -forever -usepw -create
docker inspect <container id>
o simplemente docker ps
, luego se conecta a la IP de su host con el puerto que acaba de encontrar.
Xauthority se convierte en un problema con los sistemas más nuevos. Puedo descartar cualquier protección con xhost + antes de ejecutar mis contenedores acoplables, o puedo pasar un archivo Xauthority bien preparado. Los archivos típicos de Xauthority son específicos del nombre de host. Con docker, cada contenedor puede tener un nombre de host diferente (configurado con docker run -h), pero incluso configurar el nombre de host del contenedor idéntico al sistema host no ayudó en mi caso. xeyes (me gusta este ejemplo) simplemente ignoraría la cookie mágica y no pasaría credenciales al servidor. Por lo tanto, recibimos un mensaje de error 'No se ha especificado el protocolo No se puede abrir la pantalla'
El archivo Xauthority se puede escribir de manera que el nombre de host no importe. Necesitamos establecer la familia de autenticación en 'FamilyWild'. No estoy seguro, si xauth tiene una línea de comando adecuada para esto, entonces aquí hay un ejemplo que combina xauth y sed para hacerlo. Necesitamos cambiar los primeros 16 bits de la salida nlist. El valor de FamilyWild es 65535 o 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
se puede acortar a-v $XSOCK -v $XAUTH
:0
con $DISPLAY
. Eso significa xauth nlist $DISPLAY | ...
y docker run -ti -e DISPLAY=$DISPLAY ...
. Por lo general, la PANTALLA X es :0
, pero no siempre (y especialmente no si se conecta a través de ssh -X).
/tmp/.docker.xauth
archivo con 600
permisos. Esto da como resultado que xauth dentro del contenedor acoplable no pueda leer el archivo. Puede verificar ejecutando xauth list
dentro del contenedor acoplable. He agregado chmod 755 $XAUTH
después del xauth nlist :0 | ...
comando para resolver esto.
Acabo de encontrar esta entrada de blog y quiero compartirla aquí con ustedes porque creo que es la mejor manera de hacerlo y es muy fácil.
http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/
PROS:
+ no x cosas del servidor en el contenedor docker
+ no se necesita cliente / servidor vnc
+ no ssh con reenvío x
+ contenedores docker mucho más pequeños
CONTRAS:
- usar x en el host (no destinado para el sandboxing seguro)
en caso de que el enlace falle algún día, he puesto la parte más importante aquí:
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
construir la imagen:
docker build -t firefox .
y el comando de ejecución:
docker run -ti --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
firefox
por supuesto, también puede hacer esto en el comando de ejecución con sh -c "echo script-here"
SUGERENCIA: para audio, eche un vistazo a: https://stackoverflow.com/a/28985715/2835523
apt-get -y install sudo
para crear la /etc/sudoers.d
carpeta.
$ xhost +
Con los volúmenes de datos de Docker es muy fácil exponer el zócalo de dominio Unix de xorg dentro del contenedor.
Por ejemplo, con un Dockerfile como este:
FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes
Podrías hacer lo siguiente:
$ docker build -t xeyes - < Dockerfile
$ XSOCK=/tmp/.X11-unix/X0
$ docker run -v $XSOCK:$XSOCK xeyes
Por supuesto, esto es esencialmente lo mismo que X-forwarding. Otorga al contenedor acceso completo al servidor x en el host, por lo que solo se recomienda si confía en lo que hay dentro.
Nota: Si le preocupa la seguridad, una mejor solución sería limitar la aplicación con un control de acceso obligatorio o basado en roles . Docker logra un aislamiento bastante bueno, pero fue diseñado con un propósito diferente en mente. Use AppArmor , SELinux o GrSecurity , que fueron diseñados para abordar su inquietud.
xhost +
en el host.
xhost +local
es necesario. Sin embargo, sería mejor hacer que el ~/.Xauthority
archivo esté disponible en el contenedor, para que pueda autenticarse.
Can't open display: :0
. ¿Algunas ideas?
xhost +si:localuser:$USER
autorizar solo al usuario que iniciaba el contenedor.
También puede usar el subusuario: https://github.com/timthelion/subuser
Esto le permite empaquetar muchas aplicaciones gui en docker. Firefox y emacs han sido probados hasta ahora. Sin embargo, con firefox, webGL no funciona. El cromo no funciona en absoluto.
EDITAR: ¡El sonido funciona!
EDIT2: En el tiempo desde que publiqué esto por primera vez, el subusuario ha progresado mucho. Ahora tengo un sitio web subuser.org , y un nuevo modelo de seguridad para conectarse a X11 a través del puente XPRA .
Jürgen Weigert tiene la mejor respuesta que funcionó para mí en Ubuntu, sin embargo, en OSX, Docker se ejecuta dentro de VirtualBox y, por lo tanto, la solución no funciona sin más trabajo.
Lo tengo trabajando con estos ingredientes adicionales:
Agradecería los comentarios de los usuarios para mejorar esta respuesta para OSX, no estoy seguro si el reenvío de socket para X es seguro, pero mi uso previsto es ejecutar el contenedor de Docker solo localmente.
Además, el script es un poco frágil ya que no es fácil obtener la dirección IP de la máquina, ya que está en nuestra red inalámbrica local, por lo que siempre es una IP aleatoria.
El script BASH que uso para iniciar el contenedor:
#!/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
Puedo hacer que xeyes y matplotlib funcionen con este enfoque.
Es un poco más fácil en Windows 7+ con 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.
y Error: cannot open display: VAIO:0.0
. ¿Encontró algo como esto?
Compartir la pantalla del host: 0, como se indica en algunas otras respuestas, tiene dos inconvenientes:
xev
o xinput
es posible, y el control remoto de aplicaciones host con xdotool
.--ipc=host
).Debajo de un script de ejemplo para ejecutar una imagen acoplable en Xephyr que soluciona estos problemas.
--cap-drop ALL --security-opt no-new-privileges
. Además, el usuario del contenedor no es root.El script espera algunos argumentos, primero un administrador de ventanas de host para ejecutarse en Xephyr, segundo una imagen acoplable, opcionalmente tercero un comando de imagen que se ejecutará. Para ejecutar un entorno de escritorio en Docker, use ":" en lugar de un administrador de ventanas de host.
Al cerrar la ventana de Xephyr, se finalizan las aplicaciones del contenedor acoplable. La finalización de las aplicaciones acopladas cierra la ventana de Xephyr.
Ejemplos:
xephyrdocker "openbox --sm-disable" x11docker/lxde pcmanfm
xephyrdocker : x11docker/lxde
xephyrdocker xfwm4 --device /dev/snd jess/nes /games/zelda.rom
script 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
Este script se mantiene en x11docker wiki . Un script más avanzado es x11docker que también admite funciones como aceleración de GPU, cámara web e impresora compartida, etc.
Aquí hay una solución liviana que evita tener que instalar cualquier X
servidor, vnc
servidor o sshd
demonio en el contenedor. Lo que gana en simplicidad lo pierde en seguridad y aislamiento.
Se supone que se conecta a la máquina host mediante ssh
la X11
expedición.
En la sshd
configuración del host, agregue la línea
X11UseLocalhost no
De manera que el puerto del servidor X transmitido en el host se abre en todas las interfaces (no sólo lo
) y, en particular, sobre la interfaz virtual del estibador, docker0
.
El contenedor, cuando se ejecuta, necesita acceso al .Xauthority
archivo para poder conectarse al servidor. Para hacer eso, definimos un volumen de solo lectura que apunta al directorio de inicio en el host (¡tal vez no sea una buena idea!) Y también establecemos la XAUTHORITY
variable en consecuencia.
docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority
Eso no es suficiente, también tenemos que pasar la variable DISPLAY del host, pero sustituyendo el nombre del host por la ip:
-e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")
Podemos definir un alias:
alias dockerX11run='docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority -e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")'
Y pruébalo así:
dockerX11run centos xeyes
.Xauthority
archivo en sí: -v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority
.
X11UseLocalhost
, también puede usar la opción adicional --net=host
para el docker run
comando (que se encuentra aquí ).
--net=host
es una mala idea que ahora si abres un puerto en el contenedor también estará abierto en el host ...
Si bien la respuesta de Jürgen Weigert cubre esencialmente esta solución, al principio no me quedó claro qué se estaba describiendo allí. Así que agregaré mi opinión al respecto, en caso de que alguien más necesite aclaraciones.
En primer lugar, la documentación pertinente es la página de manual de seguridad X .
Numerosas fuentes en línea sugieren simplemente montar el socket X11 unix y el ~/.Xauthority
archivo en el contenedor. Estas soluciones a menudo funcionan por suerte, sin comprender realmente por qué, por ejemplo, el usuario del contenedor termina con el mismo UID que el usuario, por lo que no hay necesidad de autorización de clave mágica.
En primer lugar, el archivo Xauthority tiene el modo 0600, por lo que el usuario del contenedor no podrá leerlo a menos que tenga el mismo UID.
Incluso si copia el archivo en el contenedor y cambia la propiedad, todavía hay otro problema. Si ejecuta xauth list
en el host y el contenedor, con el mismo Xauthority
archivo, verá diferentes entradas en la lista. Esto se debe a que xauth
filtra las entradas según dónde se ejecute.
El cliente X en el contenedor (es decir, la aplicación GUI) se comportará igual que xauth
. En otras palabras, no ve la cookie mágica para la sesión X que se ejecuta en el escritorio del usuario. En cambio, ve las entradas para todas las sesiones X "remotas" que ha abierto anteriormente (explicado a continuación).
Entonces, lo que debe hacer es agregar una nueva entrada con el nombre de host del contenedor y la misma clave hexadecimal que la cookie de host (es decir, la sesión X que se ejecuta en su escritorio), por ejemplo:
containerhostname/unix:0 MIT-MAGIC-COOKIE-1 <shared hex key>
El problema es que la cookie debe agregarse xauth add
dentro del contenedor:
touch ~/.Xauthority
xauth add containerhostname/unix:0 . <shared hex key>
De lo contrario, lo xauth
etiqueta de una manera que solo se ve fuera del contenedor.
El formato para este comando es:
xauth add hostname/$DISPLAY protocol hexkey
Donde .
representa el MIT-MAGIC-COOKIE-1
protocolo.
Nota: No es necesario copiar o enlazar-montar .Xauthority
en el contenedor. Simplemente cree un archivo en blanco, como se muestra, y agregue la cookie.
La respuesta de Jürgen Weigert se soluciona utilizando el FamilyWild
tipo de conexión para crear un nuevo archivo de autoridad en el host y copiarlo en el contenedor. Tenga en cuenta que primero extrae la clave hexadecimal para la sesión X actual del ~/.Xauthority
uso xauth nlist
.
Entonces los pasos esenciales son:
FamilyWild
tipo de conexión).Admito que no entiendo muy bien cómo FamilyWild
funciona, o cómo xauth
o los clientes X filtran las entradas del archivo Xauthority dependiendo de dónde se ejecutan. Información adicional sobre esto es bienvenida.
Si desea distribuir su aplicación Docker, necesitará un script de inicio para ejecutar el contenedor que obtenga la clave hexadecimal para la sesión X del usuario, y la importe al contenedor de una de las dos formas explicadas anteriormente.
También ayuda a comprender la mecánica del proceso de autorización:
$DISPLAY
./tmp/.X11-unix
directorio montado en el contenedor.Nota: El socket X11 Unix todavía necesita ser montado en el contenedor, o el contenedor no tendrá ruta al servidor X. La mayoría de las distribuciones deshabilitan el acceso TCP al servidor X de forma predeterminada por razones de seguridad.
Para obtener información adicional y comprender mejor cómo funciona la relación cliente / servidor X, también es útil ver el caso de ejemplo de reenvío SSH X:
$DISPLAY
en la sesión SSH para apuntar a su propio servidor X.xauth
para crear una nueva cookie para el host remoto y la agrega a los Xauthority
archivos tanto para usuarios locales como remotos.Esto no es liviano, pero es una buena solución que le da paridad a las características de Docker con virtualización de escritorio completa. Tanto Xfce4 como IceWM para Ubuntu y CentOS funcionan, y la noVNC
opción facilita el acceso a través de un navegador.
https://github.com/ConSol/docker-headless-vnc-container
Se ejecuta noVNC
tan bien como tigerVNC
vncserver. Luego se llama startx
dado Administrador de ventanas. Además, libnss_wrapper.so
se utiliza para emular la administración de contraseñas para los usuarios.
xpra
en Docker, que es X sin raíz. xpra
Era la IMO más adecuada y es más eficiente que VNC.
--device /dev/...
a la ventana acoplable y establezca los --cap
privilegios necesarios . Eso anula el propósito de la contención, pero puede pasar a través de dispositivos. Creo que con algunos ajustes debería ser posible ejecutar GNOME / KDE bajo VNC. Ejecuté múltiples X en la ventana acoplable con tarjetas nvidia (sin VNC o Xpra), por lo que eso es factible.
La solución dada en http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ parece ser una forma fácil de iniciar aplicaciones GUI desde dentro de los contenedores (intenté con Firefox sobre ubuntu 14.04) pero descubrí que se requiere un pequeño cambio adicional a la solución publicada por el autor.
Específicamente, para ejecutar el contenedor, el autor ha mencionado:
docker run -ti --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
firefox
Pero descubrí que (basado en un comentario particular en el mismo sitio) que dos opciones adicionales
-v $HOME/.Xauthority:$HOME/.Xauthority
y
-net=host
debe especificarse al ejecutar el contenedor para que firefox funcione correctamente:
docker run -ti --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $HOME/.Xauthority:$HOME/.Xauthority \
-net=host \
firefox
He creado una imagen acoplable con la información en esa página y estos hallazgos adicionales: https://hub.docker.com/r/amanral/ubuntu-firefox/
/tmp/.X11-unix
zócalo. Simplemente funciona con montaje .Xauthority
y --net=host
.
/tmp/.X11-unix
como volumen ya no funciona, ya que Docker rechaza silenciosamente los montajes de volumen de directorios fijos.
--network=host
hace. Le da a su contenedor acceso completo a la pila de red del host, lo que puede ser indeseable, dependiendo de lo que esté tratando de hacer. Si solo está jugando con la ejecución de GUI en contenedores en su escritorio, entonces no debería importar.
Hay otra solución de lord.garbage para ejecutar aplicaciones GUI en un contenedor sin usar el reenvío VNC, SSH y X11. Se menciona aquí también.
Si desea ejecutar una aplicación GUI sin cabeza, lea aquí . Lo que debe hacer es crear un monitor virtual con xvfb
u otro software similar. Esto es muy útil si desea ejecutar pruebas de selenio, por ejemplo, con navegadores.
Algo que no se menciona en ninguna parte es que algunos softwares en realidad usan sand-boxing con contenedores de Linux. Entonces, por ejemplo, Chrome nunca se ejecutará normalmente si no usa el indicador apropiado --privileged
al ejecutar el contenedor.
Llego tarde a la fiesta, pero para los usuarios de Mac que no quieren seguir el camino de XQuartz, aquí hay un ejemplo de trabajo que construye una imagen de Fedora, con un entorno de escritorio (xfce) usando Xvfb
y VNC
. Es simple y funciona:
En una Mac, puede acceder a ella usando la aplicación Compartir pantalla (predeterminada), conectándose a 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
Consulte el archivo Léame vinculado para ver los comandos de compilación y ejecución si lo desea / necesita.
Según la respuesta de Jürgen Weigert , tengo algunas mejoras:
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
La única diferencia es que crea un directorio $ XAUTH_DIR que se usa para colocar el archivo $ XAUTH y montar el directorio $ XAUTH_DIR en lugar del archivo $ XAUTH en el contenedor acoplable.
El beneficio de este método es que puede escribir un comando en /etc/rc.local que es crear una carpeta vacía llamada $ XAUTH_DIR en / tmp y cambiar su modo a 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
Cuando se reinicia el sistema, antes del inicio de sesión del usuario, Docker montará el directorio $ XAUTH_DIR automáticamente si la política de reinicio del contenedor es "siempre". Después del inicio de sesión del usuario, puede escribir un comando en ~ / .profile que es crear el archivo $ XAUTH, luego el contenedor usará automáticamente este archivo $ 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
Después de todo, el contenedor obtendrá automáticamente el archivo Xauthority cada vez que el sistema se reinicie y el usuario inicie sesión.
Las otras soluciones deberían funcionar, pero aquí hay una solución para docker-compose
.
Para corregir ese error, debe pasar $ DISPLAY y .X11-unix a Docker, así como otorgar al usuario que inició Docker acceso a xhost.
Dentro del docker-compose.yml
archivo:
version: '2'
services:
node:
build: .
container_name: node
environment:
- DISPLAY
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix
En terminal o script:
xhost +si:localuser:$USER
xhost +local:docker
export DISPLAY=$DISPLAY
docker-compose up
Para renderizar OpenGL con el controlador Nvidia, use la siguiente imagen:
https://github.com/thewtex/docker-opengl-nvidia
Para otras implementaciones de OpenGL, asegúrese de que la imagen tenga la misma implementación que el host.
Similar a la respuesta de @Nick , pero su solución no funcionó para mí.
Primero instale socat haciendo brew install socat
e instale XQuartz ( https://www.xquartz.org/ )
Luego siguió estos pasos aquí ( http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ ) en la sección de comentarios:
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
También pude lanzar CLion desde mi contenedor de Debian Docker.
Docker con red BRIDGE. para Ubuntu 16.04 con display manager lightdm:
cd /etc/lightdm/lightdm.conf.d
sudo nano user.conf
[Seat:*]
xserver-allow-tcp=true
xserver-command=X -listen tcp
puedes usar más permisos privados
xhost +
docker run --volume="$HOME/.Xauthority:/root/.Xauthority:rw" --env="DISPLAY=$HOST_IP_IN_BRIDGE_NETWORK:0" --net=bridge $container_name
Otra respuesta en caso de que ya hayas creado la imagen:
invocar docker sin sudo ( Cómo solucionar el docker: se ha denegado el permiso )
comparta el mismo USUARIO y home & passwd entre el host y el contenedor compartido (consejos: use la identificación de usuario en lugar del nombre de usuario)
la carpeta de desarrollo para que las bibliotecas dependientes del controlador funcionen bien
más X11 adelante.
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
usted puede preguntar, ¿cuál es el punto de usar Docker si tantas cosas son iguales? bueno, una de las razones por las que puedo pensar es para superar el infierno de la dependencia del paquete ( https://en.wikipedia.org/wiki/Dependency_hell ).
Entonces, este tipo de uso es más adecuado para el desarrollador, creo.
echo ~
: / home / $ {USER} --user = id -u ${USER}
--env = "DISPLAY" --volume = "/ etc / passwd: / etc / passwd: ro "-it REPO: TAG / bin / bash
Me las arreglé para ejecutar una secuencia de vídeo desde una cámara USB utilizando opencv
en docker
los siguientes pasos:
Dejar que Docker acceda al servidor X
xhost +local:docker
Cree el socket X11 Unix y el archivo de autenticación X
XSOCK=/tmp/.X11-unix
XAUTH=/tmp/.docker.xauth
Agregar permisos adecuados
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
Establezca la velocidad de representación de Qt en "nativa", para que no omita el motor de representación X11
export QT_GRAPHICSSYSTEM=native
Dígale a Qt que no use MIT-SHM (memoria compartida), de esa manera también debería ser más seguro en cuanto a seguridad
export QT_X11_NO_MITSHM=1
Actualice el comando de ejecución de Docker
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
Nota: Cuando finalice el proyecto, devuelva los controles de acceso a su valor predeterminado: xhost -local:docker
Más detalles: Uso de GUI con Docker