x11 - graphical - ¿Puede ejecutar aplicaciones GUI en un contenedor Docker?
docker container graphical interface (19)
¿Cómo puedes ejecutar aplicaciones GUI en un contenedor Docker ?
¿Hay alguna imagen que configure vncserver
o algo para que pueda, por ejemplo, agregar un cajón de arena de Speedbump adicional alrededor de Firefox?
OSX
Jürgen Weigert tiene la mejor respuesta que me funcionó en Ubuntu, sin embargo, en OSX, la ventana acoplable se ejecuta dentro de VirtualBox, por lo que la solución no funciona sin un poco más de trabajo.
Lo tengo trabajando con estos ingredientes adicionales:
- Xquartz (OSX ya no se envía con el servidor X11)
- reenvío de socket con socat (brew install socat)
- Bash script para lanzar el contenedor
Apreciaría los comentarios de los usuarios para mejorar esta respuesta para OSX, no estoy seguro de si el envío de socket para X es seguro, pero mi uso previsto es para ejecutar el contenedor de la ventana acoplable localmente.
Además, la secuencia de comandos es un poco frágil porque 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 lanzar 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
Soy capaz de hacer que xeyes y matplotlib trabajen con este enfoque.
Windows 7+
Es un poco más fácil en Windows 7+ con MobaXterm:
- Instalar MobaXterm para windows
- Iniciar MobaXterm
- Configurar el servidor X: Configuración -> X11 (pestaña) -> configurar el acceso remoto X11 a completo
- Utilice este script BASH para iniciar el contenedor
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
OSX (10.13.6, sierra alta)
Similar a la respuesta de , 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í ( 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.
Acabo de encontrar esta entrada de blog y quiero compartirla aquí contigo porque creo que es la mejor manera de hacerlo y es muy fácil.
fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
PROS:
+ no x cosas del servidor en el contenedor docker
+ no se necesita vnc cliente / servidor
+ no ssh con x reenvío
+ contenedores portacontenedores mucho más pequeños
CONTRAS:
- usando x en el host (no está diseñado para un sandboxing seguro)
En caso de que el enlace falle algún día, he puesto aquí la parte más importante:
archivo docker:
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 el audio, eche un vistazo a: https://.com/a/28985715/2835523
Aquí hay una solución liviana que evita tener que instalar cualquier servidor X
, servidor vnc
o demonio sshd
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
con el reenvío X11
.
En la configuración sshd
del host, agregue la línea
X11UseLocalhost no
De modo que el puerto del servidor X reenviado en el host se abra en todas las interfaces (no solo lo
) y, en particular, en la interfaz virtual de Docker, docker0
.
El contenedor, cuando se ejecuta, necesita acceso al archivo .Xauthority
para que pueda conectarse al servidor. Para hacer eso, definimos un volumen de solo lectura que apunta al directorio de inicio en el host (¡quizás no sea una buena idea!) Y también configuramos la variable XAUTHORITY
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 de 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 probarlo así:
dockerX11run centos xeyes
Basado en 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 de $ XAUTH en el contenedor de la ventana acoplable.
La ventaja de este método es que puede escribir un comando en /etc/rc.local que consiste en 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 de que el usuario inicie sesión, la ventana acoplable montará el directorio $ XAUTH_DIR automáticamente si la política de reinicio del contenedor es "siempre". Después de que el usuario inicie sesión, puede escribir un comando en ~ / .profile que consiste en 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.
Compartir la pantalla del host: 0, como se indica en algunas otras respuestas, tiene dos inconvenientes:
- Se rompe el aislamiento del contenedor debido a algunas fugas de seguridad de X. Por ejemplo, es posible el
xinput
teclas conxev
oxinput
, y el control remoto de aplicaciones host conxdotool
. - Las aplicaciones pueden tener fallos de representación y errores de acceso a RAM incorrectos debido a la falta de memoria compartida para la extensión X MIT-SHM. (También puede solucionarse con la opción de degradación de aislamiento
--ipc=host
).
Debajo de un script de ejemplo para ejecutar una imagen de ventana acoplable en Xephyr que resuelve estos problemas.
- Evita las fugas de seguridad de X ya que las aplicaciones de la ventana acoplable se ejecutan en un servidor X anidado.
- MIT-SHM está deshabilitado para evitar fallos de acceso a la RAM.
- La seguridad del contenedor se mejora con
--cap-drop ALL --security-opt no-new-privileges
. Además, el usuario contenedor no es root. - Se crea una cookie X para restringir el acceso a la pantalla Xephyr.
La secuencia de comandos espera algunos argumentos, primero un administrador de ventanas del host para ejecutarse en Xephyr, segundo una imagen de ventana acoplable y, opcionalmente, un tercer comando de imagen para ser ejecutado. Para ejecutar un entorno de escritorio en la ventana acoplable, use ":" en lugar de un administrador de ventanas del host.
Al cerrar la ventana Xephyr se terminan las aplicaciones de contenedores de la ventana acoplable. La finalización de las aplicaciones acopladas cierra la ventana 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
Con los volúmenes de datos de la ventana acoplable es muy fácil exponer el socket 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
Esto, por supuesto, es esencialmente lo mismo que X-forwarding. Le 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 mandatory- control de acceso mandatory- o role-based- . Docker logra un buen aislamiento, pero fue diseñado con un propósito diferente en mente. Use AppArmor , SELinux o GrSecurity , que fueron diseñados para abordar su inquietud.
Esto no es liviano, pero es una buena solución que brinda paridad de características de la ventana acoplable con la virtualización completa del escritorio. Tanto Xfce4 como IceWM para Ubuntu y CentOS funcionan, y la opción noVNC
facilita el acceso a través de un navegador.
https://github.com/ConSol/docker-headless-vnc-container
Funciona noVNC
así como también el tigerVNC
vncserver de tigerVNC
. Luego llama a startx
para un gestor de ventanas dado. Además, libnss_wrapper.so
se utiliza para emular la administración de contraseñas para los usuarios.
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 here también.
La solución dada en 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 (lo intenté con Firefox sobre ubuntu 14.04) pero encontré 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 encontré que (basado en un comentario particular en el mismo sitio) que dos opciones adicionales
-v $HOME/.Xauthority:$HOME/.Xauthority
y
-net=host
debe especificarse mientras se ejecuta 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/
Llego tarde a la fiesta, pero para los usuarios de Mac que no quieren seguir la ruta de XQuartz, aquí hay un ejemplo Xvfb
que construye una imagen de Fedora, con un entorno de escritorio (xfce) utilizando Xvfb
y VNC
. Es simple, y funciona:
- https://github.com/ddual/docker_recipes#fedora-with-an-x-window-system
- https://github.com/ddual/docker_recipes/tree/master/fedora_gui
En una Mac, solo puede acceder a ella utilizando 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
Verifique el https://github.com/ddual/docker_recipes#fedora-with-an-x-window-system vinculado para compilar y ejecutar comandos si lo desea o necesita.
Para la representación de 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.
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 añadiré mi opinión sobre el tema, en caso de que alguien más necesite una aclaración.
En primer lugar, la documentación relevante es la página de manual de seguridad de X.
Numerosas fuentes en línea sugieren simplemente montar el socket unix X11 y el archivo ~/.Xauthority
en el contenedor. Estas soluciones a menudo funcionan por suerte, sin entender realmente por qué, por ejemplo, el usuario del contenedor termina con el mismo UID que el usuario, por lo que no hay necesidad de una 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 archivo Xauthority
, 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 X sesiones "remotas" que ha abierto anteriormente (se explica 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 del host (es decir, la sesión de 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 se debe agregar con xauth add
dentro del contenedor:
touch ~/.Xauthority
xauth add containerhostname/unix:0 . <shared hex key>
De lo contrario, xauth
etiqueta de manera que solo se vea fuera del contenedor.
El formato para este comando es:
xauth add hostname/$DISPLAY protocol hexkey
Donde Representa el protocolo MIT-MAGIC-COOKIE-1
.
Nota: No es necesario copiar o vincular .Xauthority
en el contenedor. Simplemente cree un archivo en blanco, como se muestra, y agregue la cookie.
La respuesta de Jürgen Weigert FamilyWild
esto al utilizar el tipo de conexión FamilyWild
para crear un nuevo archivo de autoridad en el host y copiarlo en el contenedor. Tenga en cuenta que primero extrae la clave hexadecimal de la sesión X actual de ~/.Xauthority
usando xauth nlist
.
Así que los pasos esenciales son:
- Extraiga la clave hexadecimal de la cookie para la sesión X actual del usuario.
- Cree un nuevo archivo de Xauthority en el contenedor, con el nombre de host del contenedor y la clave hexadecimal compartida (o cree una cookie con el tipo de conexión
FamilyWild
).
Admito que no entiendo muy bien cómo funciona FamilyWild
, o cómo los clientes xauth
o X filtran las entradas del archivo de Xauthority dependiendo de dónde se ejecuten. Información adicional sobre esto es bienvenida.
Si desea distribuir su aplicación Docker, necesitará un script de inicio para ejecutar el contenedor que obtiene la clave hexadecimal para la sesión X del usuario, y lo importa al contenedor de una de las dos formas explicadas anteriormente.
También ayuda a comprender la mecánica del proceso de autorización:
- Un cliente X (es decir, la aplicación GUI) que se ejecuta en el contenedor busca en el archivo de Xauthority una entrada de cookie que coincida con el nombre de host del contenedor y el valor de
$DISPLAY
. - Si se encuentra una entrada coincidente, el cliente X lo pasa con su solicitud de autorización al servidor X, a través del socket apropiado en el directorio
/tmp/.X11-unix
montado en el contenedor.
Nota: El zócalo X11 Unix aún necesita ser montado en el contenedor, o el contenedor no tendrá una ruta al servidor X. La mayoría de las distribuciones deshabilitan el acceso TCP al servidor X por defecto por razones de seguridad.
Para obtener información adicional, y para comprender mejor cómo funciona la relación cliente / servidor X, también es útil observar el caso de ejemplo del reenvío SSH X:
- El servidor SSH que se ejecuta en una máquina remota emula su propio servidor X.
- Establece el valor de
$DISPLAY
en la sesión SSH para que apunte a su propio servidor X. - Utiliza
xauth
para crear una nueva cookie para el host remoto y la agrega a los archivos deXauthority
para los usuarios locales y remotos. - Cuando se inician las aplicaciones GUI, hablan con el servidor X emulado de SSH.
- El servidor SSH reenvía estos datos al cliente SSH en su escritorio local.
- El cliente SSH local envía los datos a la sesión del servidor X que se ejecuta en su escritorio, como si el cliente SSH fuera realmente un cliente X (es decir, la aplicación GUI).
- El servidor X utiliza los datos recibidos para representar la GUI en su escritorio.
- Al comienzo de este intercambio, el cliente X remoto también envía una solicitud de autorización, utilizando la cookie que se acaba de crear. El servidor X local lo compara con su copia local.
Si desea ejecutar una aplicación GUI sin cabeza, lea here . Lo que debe hacer es crear un monitor virtual con xvfb
u otro software similar. Esto es muy útil si desea ejecutar pruebas de Selenium, por ejemplo, con navegadores.
Algo que no se menciona en ninguna parte es que algunos programas en realidad usan cajas de arena con contenedores de Linux. Así, por ejemplo, Chrome nunca se ejecutará normalmente si no utiliza el indicador adecuado --privileged
al ejecutar el contenedor.
Simplemente puede instalar un vncserver junto con Firefox :)
Empujé una imagen, vnc / firefox, aquí: docker pull creack/firefox-vnc
La imagen se ha realizado 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 ejecutando VNC con la contraseña 1234
:
Para Docker versión 1.3 o más reciente:
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
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. Con Firefox, webGL no funciona sin embargo. El cromo no funciona en absoluto.
EDIT: sonido funciona!
EDIT2: En el tiempo desde que publiqué esto por primera vez, el subusuario ha progresado enormemente. Ahora tengo un sitio web subuser.org y un nuevo modelo de seguridad para conectar a X11 a través del puente XPRA .
Xauthority se convierte en un problema con los sistemas más nuevos. Puedo descartar cualquier protección con xhost + antes de ejecutar mis contenedores de la ventana acoplable, o puedo pasar un archivo de Xauthority bien preparado. Los archivos típicos de Xauthority son específicos del nombre de host. Con la ventana acoplable, cada contenedor puede tener un nombre de host diferente (configurado con la ejecución de la ventana acoplable -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 ninguna credencial al servidor. Por lo tanto, aparece un mensaje de error ''No se ha especificado el protocolo No se puede abrir la pantalla''
El archivo Xauthority se puede escribir de forma 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, así que aquí hay un ejemplo que combina xauth y sed para hacer eso. 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
Puede permitir que el usuario de Docker (aquí: root) acceda a la pantalla 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
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 la ventana acoplable, así como otorgar al usuario que inició la conexión a la base de la ventana acoplable.
Dentro de docker-compose.yml: 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