Pouvez-vous exécuter des applications GUI dans un conteneur Docker?


409

Comment pouvez-vous exécuter des applications GUI dans un conteneur Docker ?

Y a-t-il des images qui sont configurées vncserverou quelque chose pour que vous puissiez - par exemple - ajouter un sandbox speedbump supplémentaire autour de Firefox?


Cette question semble concerner uniquement Linux (en fonction de l'âge et du contenu des réponses) et non Windows. Si oui, pouvons-nous modifier le titre pour clarifier cela? Merci
UuDdLrLrSs


Réponses:


238

Vous pouvez simplement installer un serveur vnc avec Firefox :)

J'ai poussé une image, vnc / firefox, ici: docker pull creack/firefox-vnc

L'image a été réalisée avec ce 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'

Cela va créer un conteneur Docker exécutant VNC avec le mot de passe 1234:

Pour Docker version 18 ou plus récente:

docker run -p 5900:5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create

Pour Docker version 1.3 ou plus récente:

docker run -p 5900 -e HOME=/ creack/firefox-vnc x11vnc -forever -usepw -create

Pour Docker avant la version 1.3:

docker run -p 5900 creack/firefox-vnc x11vnc -forever -usepw -create

2
Comment utiliser un client VNC pour visualiser cela à distance? La saisie du port IP + ne semble pas fonctionner.
user94154

17
Tout d'abord, vous devez vérifier le port alloué (en faisant docker inspect <container id>ou simplement docker ps, puis vous vous connectez à l'IP de votre hôte avec le port que vous venez de trouver.
creack

9
l'image creackfirefox-vnc échoue avec une erreur: Entrez le mot de passe VNC: stty: entrée standard: ioctl inapproprié pour les fgets du périphérique: Aucun fichier ou répertoire stty: entrée standard: ioctl inapproprié pour le périphérique x11vnc -usepw: n'a pas trouvé de mot de passe à utiliser.
alfonsodev

6
Bien utiliser Docker> Exécuter des applications GUI avec Docker fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
Dennis C

7
Il n'y a pas de nom d'utilisateur, le mot de passe est clairement indiqué dans la réponse et tout client vnc fera l'affaire. Dans mon cas, j'aime l'osx natif. (à partir du Finder, appuyez sur commande + K et connectez-vous à vnc: // <docker ip>: <port exposé du conteneur>)
creack

195

Xauthority devient un problème avec les nouveaux systèmes. Je peux soit supprimer toute protection avec xhost + avant d'exécuter mes conteneurs Docker, soit transmettre un fichier Xauthority bien préparé. Les fichiers Xauthority typiques sont spécifiques au nom d'hôte. Avec docker, chaque conteneur peut avoir un nom d'hôte différent (défini avec docker run -h), mais même définir le nom d'hôte du conteneur identique au système hôte n'a pas aidé dans mon cas. xeyes (j'aime cet exemple) ignorerait simplement le cookie magique et ne transmettrait aucune information d'identification au serveur. Par conséquent, nous obtenons un message d'erreur «Aucun protocole spécifié Impossible d'ouvrir l'affichage»

Le fichier Xauthority peut être écrit de manière à ce que le nom d'hôte n'ait pas d'importance. Nous devons définir la famille d'authentification sur «FamilyWild». Je ne suis pas sûr, si xauth a une ligne de commande appropriée pour cela, alors voici un exemple qui combine xauth et sed pour le faire. Nous devons changer les 16 premiers bits de la sortie nlist. La valeur de FamilyWild est 65535 ou 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

8
Juste une note, -v $XSOCK:$XSOCK -v $XAUTH:$XAUTHpeut être raccourci à-v $XSOCK -v $XAUTH
Piotr Aleksander Chmielowski

2
@PiotrAleksanderChmielowski qui n'a pas fonctionné pour moi, Docker version 1.12.0, build 8eab29e
tbc0

14
@Dirk: Vous voudrez peut-être remplacer :0par $DISPLAY. Cela signifie xauth nlist $DISPLAY | ...et docker run -ti -e DISPLAY=$DISPLAY .... Habituellement, le X DISPLAY l'est :0, mais pas toujours (et surtout pas si vous vous connectez via ssh -X).
johndodo

4
Sur Ubuntu 16.04, xauth crée le /tmp/.docker.xauthfichier avec des 600autorisations. Il en résulte que xauth dans le conteneur Docker ne peut pas lire le fichier. Vous pouvez vérifier en exécutant xauth listdans le conteneur Docker. J'ai ajouté chmod 755 $XAUTHaprès la xauth nlist :0 | ...commande pour résoudre ce problème.
Abai

2
@Abai Pourquoi utiliser 755, si 444 ou 644 suffisent?
Daniel Alder

68

Je viens de trouver cette entrée de blog et je veux la partager ici avec vous parce que je pense que c'est la meilleure façon de le faire et c'est si facile.

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

AVANTAGES:
+ pas de serveur x dans le conteneur docker
+ pas de client / serveur vnc nécessaire
+ pas de ssh avec transfert x
+ conteneurs docker beaucoup plus petits

CONTRE:
- utilisation de x sur l'hôte (non destiné au sandbox sécurisé)

au cas où le lien échouerait un jour, j'ai mis la partie la plus importante ici:
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

construire l'image:

docker build -t firefox .

et la commande run:

docker run -ti --rm \
   -e DISPLAY=$DISPLAY \
   -v /tmp/.X11-unix:/tmp/.X11-unix \
   firefox

bien sûr, vous pouvez également le faire dans la commande d'exécution avec sh -c "echo script-here"

CONSEIL: pour l'audio, consultez: https://stackoverflow.com/a/28985715/2835523


Comment puis-je faire cela sur Windows 7? Dois-je installer un serveur X?
promenades

3
Comme la plupart des réponses ici, cela ne s'applique qu'à Unix, je pense - jusqu'à ce que Windows prenne en charge le système de fenêtres du serveur X.
A. Binzxxxxxx

Pensez-vous que cela pourrait fonctionner si j'installe le serveur X sur Windows ou même que j'emballe un serveur X dans mon conteneur Docker?
promenades

1
Je pense que vous devez également installer dans Dockerfile apt-get -y install sudopour créer un /etc/sudoers.ddossier.
mulg0r

1
il peut également être nécessaire d'autoriser les connexions à X à partir de tout hôte avec$ xhost +
Bandoos

52

Avec les volumes de données Docker, il est très facile d'exposer la socket de domaine Unix de xorg à l'intérieur du conteneur.

Par exemple, avec un Dockerfile comme celui-ci:

FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes

Vous pouvez effectuer les opérations suivantes:

$ docker build -t xeyes - < Dockerfile
$ XSOCK=/tmp/.X11-unix/X0
$ docker run -v $XSOCK:$XSOCK xeyes

Bien sûr, cela est essentiellement le même que le transfert X. Il accorde au conteneur un accès complet au xserver sur l'hôte, il n'est donc recommandé que si vous faites confiance à ce qu'il contient.

Remarque: Si vous êtes préoccupé par la sécurité, une meilleure solution serait de confiner l'application avec un contrôle d'accès obligatoire ou basé sur les rôles. Docker atteint une assez bonne isolation, mais il a été conçu dans un but différent. Utilisez AppArmor , SELinux ou GrSecurity , qui ont été conçus pour répondre à votre préoccupation.


5
Vous devez également autoriser l'accès au serveur X à partir d'autres hôtes à l'aide d'un outil comme xhost. Pour l'ouvrir complètement, utilisez xhost +sur l'hôte.
Tully

3
@Tully seulement xhost +localest nécessaire. Il serait cependant préférable de rendre le ~/.Xauthorityfichier disponible dans le conteneur, afin qu'il puisse s'authentifier.
Aryeh Leib Taurog

3
avez-vous réussi à le faire fonctionner sur un Mac (en utilisant boot2docker)?
Karl Forner

4
Cela fonctionnait plutôt bien pour moi sur un ordinateur portable Ubuntu 14.04 avec docker 1.5 plus tôt; mais échoue maintenant pour moi sur Ubuntu 15.04, docker 1.6.2, avec l'erreur Can't open display: :0. Des idées?
cboettig

6
xhost +si:localuser:$USERJ'autoriser que l'utilisateur à partir du conteneur.
Nick Breen

26

Vous pouvez également utiliser un sous-utilisateur: https://github.com/timthelion/subuser

Cela vous permet de regrouper de nombreuses applications GUI dans Docker. Firefox et emacs ont été testés jusqu'à présent. Avec firefox, webGL ne fonctionne pas cependant. Le chrome ne fonctionne pas du tout.

EDIT: Le son fonctionne!

EDIT2: Depuis la première fois que j'ai posté ceci, le sous-utilisateur a beaucoup progressé. J'ai maintenant un site Web up subuser.org , et un nouveau modèle de sécurité pour se connecter à X11 via un pont XPRA .


3
Veuillez noter que le sous-utilisateur est encore très nouveau et relativement non testé. Si vous rencontrez des problèmes, veuillez soumettre des rapports de bogues!
timthelion

J'éviterais X11 s'il y a un moyen possible. Votre application killer exécuterait le proxy tor dans docker et exécuterait un navigateur complet avec des plugins dans un docker enfant de telle sorte que le pare-feu, etc., forcerait tout le réseau à sortir via le docker tor. Cela tournerait autour du bundle actuel du navigateur tor pour la convivialité du Web, car vous laisseriez passer un contenu riche.
Will

1
Le problème est-il pour vous avec la sécurité X11? Ou est-ce que vous voulez que cela fonctionne avec Windows? Ou que vous souhaitez que cela fonctionne à distance? Tout ce qui précède? Je pense que faire ce travail avec vnc est tout à fait possible (bien que je n'en ferais pas la méthode par défaut car cela ajoute une dépendance à vnc). Faire fonctionner un sous-utilisateur à distance n'est pas vraiment possible / significatif. Il y a aussi ceci: github.com/rogaha/docker-desktop mais d'après les rapports de bogues, il semble que xpra soit inutilisable dans la vie réelle.
timthelion

24

OSX

Jürgen Weigert a la meilleure réponse qui a fonctionné pour moi sur Ubuntu, cependant sur OSX, docker s'exécute à l'intérieur de VirtualBox et donc la solution ne fonctionne pas sans plus de travail.

Je l'ai avec ces ingrédients supplémentaires:

  1. Xquartz (OSX n'est plus livré avec le serveur X11)
  2. transfert de socket avec socat (brew install socat)
  3. script bash pour lancer le conteneur

J'apprécierais les commentaires des utilisateurs pour améliorer cette réponse pour OSX, je ne sais pas si le transfert de socket pour X est sécurisé, mais mon utilisation prévue est d'exécuter le conteneur Docker localement uniquement.

De plus, le script est un peu fragile en ce qu'il n'est pas facile d'obtenir l'adresse IP de la machine car elle se trouve sur notre réseau local sans fil, il s'agit donc toujours d'une adresse IP aléatoire.

Le script BASH que j'utilise pour lancer le conteneur:

#!/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

Je suis capable de faire fonctionner xeyes et matplotlib avec cette approche.

Windows 7+

C'est un peu plus facile sur Windows 7+ avec MobaXterm:

  1. Installer MobaXterm pour Windows
  2. Démarrez MobaXterm
  3. Configurer le serveur X: Paramètres -> X11 (onglet) -> définir l' accès à distance X11 sur complet
  4. Utilisez ce script BASH pour lancer le conteneur

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 fonctionnant sur PC


Je ne comprenais pas ce que vous vouliez dire par le script bash - comment l'exécuter dans Windows?
deller

@deller Je fais du développement logiciel sur Windows en utilisant GIT, j'ai donc le shell GIT-bash à ma disposition.
Nick

J'ai suivi les étapes. Cependant, je reçois error: XDG_RUNTIME_DIR not set in the environment.et Error: cannot open display: VAIO:0.0. Avez-vous rencontré quelque chose comme ça?
user3275095

1
J'obtiens une erreur concernant l'utilisateur introuvable, c'est-à-dire "aucune entrée correspondante dans le fichier passwd". Des pistes?
promenades

19

Partage de l'affichage de l'hôte: 0, comme indiqué dans certaines autres réponses, présente deux inconvénients:

  • Il brise l'isolement du conteneur en raison de certaines fuites de sécurité X. Par exemple, le keylogging avec xevou xinputest possible, et le contrôle à distance des applications hôtes avec xdotool.
  • Les applications peuvent avoir des problèmes de rendu et de mauvaises erreurs d'accès à la RAM en raison de la mémoire partagée manquante pour l'extension X MIT-SHM. (Peut également être corrigé avec l'option de dégradation de l'isolement --ipc=host).

Ci-dessous un exemple de script pour exécuter une image docker dans Xephyr qui résout ce problème.

  • Il évite les fuites de sécurité X lorsque les applications Docker s'exécutent sur un serveur X imbriqué.
  • MIT-SHM est désactivé pour éviter les échecs d'accès à la RAM.
  • La sécurité des conteneurs est améliorée avec --cap-drop ALL --security-opt no-new-privileges. L'utilisateur du conteneur n'est pas non plus root.
  • Un cookie X est créé pour restreindre l'accès à l'affichage Xephyr.

Le script attend certains arguments, d'abord un gestionnaire de fenêtres hôtes à exécuter dans Xephyr, deuxièmement une image docker, éventuellement une troisième commande image à exécuter. Pour exécuter un environnement de bureau dans Docker, utilisez ":" au lieu d'un gestionnaire de fenêtres hôte.

La fermeture de la fenêtre Xephyr met fin aux applications de conteneur Docker. La fermeture des applications ancrées ferme la fenêtre Xephyr.

Exemples:

  • 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

Ce script est maintenu sur le wiki x11docker . Un script plus avancé est x11docker qui prend également en charge des fonctionnalités telles que l'accélération GPU, le partage de webcam et d'imprimante, etc.


18

Voici une solution légère qui évite d'avoir à installer n'importe quel Xserveur, vncserveur ou sshddémon sur le conteneur. Ce qu'il gagne en simplicité, il le perd en sécurité et en isolement.

Il suppose que vous vous connectez à la machine hôte à l'aide sshde la X11redirection.

Dans la sshdconfiguration de l'hôte, ajoutez la ligne

X11UseLocalhost no

Alors que le port du serveur X transmis sur l'hôte est ouvert sur toutes les interfaces (pas seulement lo) et en particulier sur l'interface virtuelle Docker, docker0.

Le conteneur, lorsqu'il est exécuté, doit avoir accès au .Xauthorityfichier pour pouvoir se connecter au serveur. Pour ce faire, nous définissons un volume en lecture seule pointant vers le répertoire personnel de l'hôte (ce n'est peut-être pas une bonne idée!) Et définissons également la XAUTHORITYvariable en conséquence.

docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority

Cela ne suffit pas, nous devons également passer la variable DISPLAY de l'hôte, mais en remplaçant le nom d'hôte par l'ip:

-e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")

On peut définir un alias:

 alias dockerX11run='docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority -e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")'

Et testez-le comme ceci:

dockerX11run centos xeyes

2
(Ceci est idéal pour les applications de confiance. Pour tout type de sandbox, cependant, vous voulez éviter le transfert X.)
Le

1
Si vous préférez ne pas monter l'ensemble répertoire dans le conteneur , vous pouvez simplement monter le .Xauthorityfichier lui - même: -v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority.
Robert Haines

2
Au lieu de changer X11UseLocalhost, vous pouvez également utiliser l'option supplémentaire --net=hostpour la docker runcommande (trouvée ici ).
ingomueller.net

--net=hostest une mauvaise idée car maintenant si vous ouvrez un port dans le conteneur, il sera également ouvert dans l'hôte ...
MrR

16

Bien que la réponse de Jürgen Weigert couvre essentiellement cette solution, je ne savais pas au début ce qui était décrit ici. Je vais donc ajouter mon point de vue, au cas où quelqu'un d'autre aurait besoin de clarifications.

Tout d' abord, la documentation pertinente est la page de manuel de sécurité X .

De nombreuses sources en ligne suggèrent simplement de monter le socket Unix X11 et le ~/.Xauthorityfichier dans le conteneur. Ces solutions fonctionnent souvent par chance, sans vraiment comprendre pourquoi, par exemple, l'utilisateur du conteneur se retrouve avec le même UID que l'utilisateur, il n'y a donc pas besoin d'autorisation de clé magique.

Tout d'abord, le fichier Xauthority a le mode 0600, donc l'utilisateur du conteneur ne pourra le lire que s'il a le même UID.

Même si vous copiez le fichier dans le conteneur et changez de propriétaire, il y a encore un autre problème. Si vous exécutez xauth listsur l'hôte et le conteneur, avec le même Xauthorityfichier, vous verrez différentes entrées répertoriées. En effet, xauthfiltre les entrées en fonction de l'endroit où elles sont exécutées.

Le client X dans le conteneur (c'est-à-dire l'application GUI) se comportera de la même manière que xauth. En d'autres termes, il ne voit pas le cookie magique pour la session X en cours d'exécution sur le bureau de l'utilisateur. Au lieu de cela, il voit les entrées pour toutes les sessions X "distantes" que vous avez ouvertes précédemment (expliquées ci-dessous).

Donc, ce que vous devez faire est d'ajouter une nouvelle entrée avec le nom d'hôte du conteneur et la même clé hexadécimale que le cookie hôte (c'est-à-dire la session X en cours d'exécution sur votre bureau), par exemple:

containerhostname/unix:0   MIT-MAGIC-COOKIE-1   <shared hex key>

Le hic, c'est que le cookie doit être ajouté à l' xauth addintérieur du conteneur:

touch ~/.Xauthority
xauth add containerhostname/unix:0 . <shared hex key>

Sinon, xauthmarquez-le de manière à ce qu'il ne soit visible qu'à l'extérieur du conteneur.

Le format de cette commande est:

xauth add hostname/$DISPLAY protocol hexkey

.représente le MIT-MAGIC-COOKIE-1protocole.

Remarque: il n'est pas nécessaire de copier ou de monter-lier .Xauthoritydans le conteneur. Créez simplement un fichier vierge, comme indiqué, et ajoutez le cookie.

La réponse de Jürgen Weigert contourne ce problème en utilisant le FamilyWildtype de connexion pour créer un nouveau fichier d'autorité sur l'hôte et le copier dans le conteneur. Notez qu'il extrait d'abord la clé hexadécimale de la session X en cours d' ~/.Xauthorityutilisation xauth nlist.

Les étapes essentielles sont donc:

  • Extrayez la clé hexadécimale du cookie pour la session X actuelle de l'utilisateur.
  • Créez un nouveau fichier Xauthority dans le conteneur, avec le nom d'hôte du conteneur et la clé hexagonale partagée (ou créez un cookie avec le FamilyWildtype de connexion).

J'avoue que je ne comprends pas très bien comment FamilyWildfonctionne, ou comment xauthou les clients X filtrent les entrées du fichier Xauthority en fonction de l'endroit où elles sont exécutées. Des informations supplémentaires à ce sujet sont les bienvenues.

Si vous souhaitez distribuer votre application Docker, vous aurez besoin d'un script de démarrage pour exécuter le conteneur qui obtient la clé hexadécimale de la session X de l'utilisateur et l'importe dans le conteneur de l'une des deux manières expliquées précédemment.

Il permet également de comprendre les mécanismes du processus d'autorisation:

  • Un client X (c'est-à-dire une application graphique) exécuté dans le conteneur recherche dans le fichier Xauthority une entrée de cookie qui correspond au nom d'hôte du conteneur et à la valeur de $DISPLAY.
  • Si une entrée correspondante est trouvée, le client X la transmet avec sa demande d'autorisation au serveur X, via le socket approprié dans le /tmp/.X11-unixrépertoire monté dans le conteneur.

Remarque: Le socket Unix X11 doit toujours être monté dans le conteneur, sinon le conteneur n'aura aucun itinéraire vers le serveur X. La plupart des distributions désactivent par défaut l'accès TCP au serveur X pour des raisons de sécurité.

Pour plus d'informations et pour mieux comprendre le fonctionnement de la relation client / serveur X, il est également utile de consulter l'exemple de transfert SSH X:

  • Le serveur SSH exécuté sur une machine distante émule son propre serveur X.
  • Il définit la valeur de $DISPLAYdans la session SSH pour pointer vers son propre serveur X.
  • Il utilise xauthpour créer un nouveau cookie pour l'hôte distant et l'ajoute aux Xauthorityfichiers pour les utilisateurs locaux et distants.
  • Lorsque les applications GUI sont démarrées, elles parlent au serveur X émulé de SSH.
  • Le serveur SSH retransmet ces données au client SSH sur votre bureau local.
  • Le client SSH local envoie les données à la session du serveur X qui s'exécute sur votre bureau, comme si le client SSH était en fait un client X (c'est-à-dire une application GUI).
  • Le serveur X utilise les données reçues pour afficher l'interface graphique sur votre bureau.
  • Au début de cet échange, le client X distant envoie également une demande d'autorisation, à l'aide du cookie qui vient d'être créé. Le serveur X local le compare à sa copie locale.

12

Ce n'est pas léger mais c'est une bonne solution qui donne la parité des fonctionnalités de docker avec la virtualisation complète du bureau. Les deux Xfce4 ou IceWM pour Ubuntu et CentOS fonctionnent, et l' noVNCoption permet un accès facile via un navigateur.

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

Il fonctionne noVNCaussi bien que tigerVNCvncserver. Ensuite, il demande startxun gestionnaire de fenêtres donné. En outre, libnss_wrapper.soest utilisé pour émuler la gestion des mots de passe pour les utilisateurs.


quelqu'un a-t-il testé cela?
guilhermecgs

3
@guilhermecgs oui, et fonctionne très bien. Depuis lors, j'ai également essayé le xpradocker, qui est sans racine X. xpraétait l'OMI le mieux adapté et est plus efficace que VNC.
dashesy

Juste pour être clair ... Puis-je avoir une expérience de bureau complète (GNOME, KDE) avec cette image?
guilhermecgs

J'ai seulement essayé le Xfce4 et IceWM (qui est dans ce repo). Bien sûr, l'expérience sera limitée, par exemple, le montage de périphériques n'apparaîtra pas sur le bureau (gvfs) sauf si vous passez --device /dev/...au docker et définissez les --capprivilèges nécessaires . Cela va à l'encontre de l'objectif de confinement, mais vous pouvez passer à travers des appareils. Avec quelques ajustements, il devrait être possible, je crois, d'exécuter GNOME / KDE sous VNC. J'ai exécuté plusieurs X dans docker avec des cartes nvidia (pas de VNC ou Xpra), donc c'est certainement faisable.
dashesy

Nous ne l'avons pas essayé jusqu'à présent. Le plus grand défi à ce sujet serait de mettre en place un démon D-Bus fonctionnel. La plupart des bureaux gnome ou KDE en auront besoin. Puisse le projet ubuntu-desktop-lxde-vnc vous y aider.
toschneck

11

La solution proposée sur http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ semble être un moyen facile de démarrer des applications GUI à l'intérieur des conteneurs (j'ai essayé pour firefox par rapport à Ubuntu 14.04) mais j'ai trouvé qu'un petit changement supplémentaire est nécessaire à la solution postée par l'auteur.

Plus précisément, pour l'exécution du conteneur, l'auteur a mentionné:

    docker run -ti --rm \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    firefox

Mais j'ai trouvé que (sur la base d'un commentaire particulier sur le même site) que deux options supplémentaires

    -v $HOME/.Xauthority:$HOME/.Xauthority

et

    -net=host 

doivent être spécifiés lors de l'exécution du conteneur pour que Firefox fonctionne correctement:

    docker run -ti --rm \
    -e DISPLAY=$DISPLAY \
    -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v $HOME/.Xauthority:$HOME/.Xauthority \
    -net=host \
    firefox

J'ai créé une image docker avec les informations sur cette page et ces conclusions supplémentaires: https://hub.docker.com/r/amanral/ubuntu-firefox/


3
J'ai trouvé que vous n'avez même pas besoin de passer du /tmp/.X11-unixtout. Cela fonctionne juste avec le montage .Xauthorityet --net=host.
CMCDragonkai

2
C'est en fait la seule solution qui fonctionne de nos jours. L'utilisation de /tmp/.X11-unixas volume ne fonctionne plus, car docker refuse silencieusement les montages de volume à partir de répertoires collants.
Christian Hujer

1
Je pense que cela dépend de la distribution que vous utilisez. Vous pouvez certainement monter et monter le socket Unix X11 sur CentOS. Il est également important de comprendre ce qui se --network=hostpasse. Il donne à votre conteneur un accès complet à la pile réseau de l'hôte, ce qui peut être indésirable, selon ce que vous essayez de faire. Si vous essayez simplement d'exécuter des GUI conteneurisées sur votre bureau, cela ne devrait pas avoir d'importance.
orodbhen

7

Il y a une autre solution par lord.garbage pour exécuter des applications GUI dans un conteneur sans utiliser le transfert VNC, SSH et X11. Il est également mentionné ici .


1
C'est très bien si la sécurité n'est pas un problème. Si le but de l'amarrage de quelque chose est de l'isoler, il vaut mieux éviter que le X11 entre dans le conteneur.
Sera le

7

Si vous souhaitez exécuter une application GUI sans tête, lisez ici . Ce que vous devez faire est de créer un moniteur virtuel avec xvfbou tout autre logiciel similaire. Ceci est très utile si vous souhaitez exécuter des tests Selenium par exemple avec des navigateurs.

Quelque chose qui n'est mentionné nulle part est que certains logiciels utilisent eux-mêmes le bac à sable avec des conteneurs Linux. Ainsi, par exemple, Chrome ne fonctionnera jamais normalement si vous n'utilisez pas l'indicateur approprié --privilegedlors de l'exécution du conteneur.


6

Je suis en retard à la fête, mais pour les utilisateurs Mac qui ne veulent pas emprunter le chemin XQuartz, voici un exemple de travail qui construit une image Fedora, avec un environnement de bureau (xfce) en utilisant Xvfbet VNC. C'est simple et ça marche:

Sur un Mac, vous pouvez simplement y accéder en utilisant l'application de partage d'écran (par défaut), en vous connectant à 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

Vérifiez le fichier Lisezmoi lié pour les commandes de génération et d'exécution si vous le souhaitez / avez besoin.


5

Sur la base de la réponse de Jürgen Weigert , j'ai une amélioration:

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 seule différence est qu'il crée un répertoire $ XAUTH_DIR qui est utilisé pour placer le fichier $ XAUTH et monter le répertoire $ XAUTH_DIR au lieu du fichier $ XAUTH dans le conteneur Docker.

L'avantage de cette méthode est que vous pouvez écrire une commande dans /etc/rc.local qui consiste à créer un dossier vide nommé $ XAUTH_DIR dans / tmp et changer son mode en 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

Au redémarrage du système, avant la connexion de l'utilisateur, docker montera automatiquement le répertoire $ XAUTH_DIR si la stratégie de redémarrage du conteneur est "toujours". Après la connexion de l'utilisateur, vous pouvez écrire une commande dans ~ / .profile qui consiste à créer le fichier $ XAUTH, puis le conteneur utilisera automatiquement ce fichier $ 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

Après tout, le conteneur obtiendra automatiquement le fichier Xauthority à chaque redémarrage du système et connexion de l'utilisateur.


4

Les autres solutions devraient fonctionner, mais voici une solution pour docker-compose.

Pour corriger cette erreur, vous devez transmettre $ DISPLAY et .X11-unix à docker, ainsi qu'accorder à l'utilisateur qui a démarré docker l'accès à xhost.

Dans le docker-compose.ymlfichier:

version: '2'
services:
    node:
        build: .
        container_name: node
        environment:
            - DISPLAY
        volumes:
            - /tmp/.X11-unix:/tmp/.X11-unix

Dans le terminal ou le script:

  • xhost +si:localuser:$USER
  • xhost +local:docker
  • export DISPLAY=$DISPLAY
  • docker-compose up


3

Vous pouvez autoriser l'utilisateur Docker (ici: root) à accéder à l'écran 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

2

OSX (10.13.6, haute sierra)

Semblable à la réponse de @Nick , mais sa solution n'a pas fonctionné pour moi.

Installez d'abord socat en faisant brew install socat, et installez XQuartz ( https://www.xquartz.org/ )

Ensuite, suivez ces étapes ici ( http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ ) dans la section des commentaires:

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

J'ai également pu lancer CLion à partir de mon conteneur Docker Debian.


1

Docker avec réseau BRIDGE. pour Ubuntu 16.04 avec le gestionnaire d'affichage lightdm:

cd /etc/lightdm/lightdm.conf.d
sudo nano user.conf

[Seat:*]
xserver-allow-tcp=true
xserver-command=X -listen tcp

vous pouvez utiliser des autorisations plus privées

xhost +

docker run --volume="$HOME/.Xauthority:/root/.Xauthority:rw" --env="DISPLAY=$HOST_IP_IN_BRIDGE_NETWORK:0" --net=bridge $container_name

1

Encore une autre réponse au cas où vous auriez déjà construit l'image:

  1. invoquer le docker sans sudo ( Comment réparer le docker: problème de permission refusée )

  2. partager le même UTILISATEUR & home & passwd entre l'hôte et le partage de conteneur (astuces: utiliser l'ID utilisateur au lieu du nom d'utilisateur)

  3. le dossier de développement pour que les bibliothèques dépendantes du pilote fonctionnent correctement

  4. plus X11 vers l'avant.

    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

vous pouvez demander, quel est l'intérêt d'utiliser docker si tant de choses sont les mêmes? eh bien, une raison pour laquelle je peux penser est de surmonter l'enfer de la dépendance des packages ( https://en.wikipedia.org/wiki/Dependency_hell ).

Donc ce type d'utilisation est plus adapté au développeur je pense.


C'est le seul qui fonctionnerait pour moi. Pour mes besoins, j'ai pu le réduire à ceci: docker run --network = host --volume = echo ~: / home / $ {USER} --user = id -u ${USER}--env = "DISPLAY" --volume = "/ etc / passwd: / etc / passwd: ro "-it REPO: TAG / bin / bash
user1145922

1

J'ai réussi à exécuter un flux vidéo à partir d'une caméra USB à l'aide opencvde dockeren suivant ces étapes:

  1. Laissez Docker accéder au serveur X

    xhost +local:docker
    
  2. Créez le socket Unix X11 et le fichier d'authentification X

    XSOCK=/tmp/.X11-unix
    XAUTH=/tmp/.docker.xauth
    
  3. Ajouter les autorisations appropriées

    xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
    
  4. Réglez la vitesse de rendu Qt sur "native" pour qu'elle ne contourne pas le moteur de rendu X11

    export QT_GRAPHICSSYSTEM=native
    
  5. Dites à Qt de ne pas utiliser MIT-SHM (mémoire partagée) - de cette façon, cela devrait également être plus sûr en termes de sécurité

    export QT_X11_NO_MITSHM=1
    
  6. Mettre à jour la commande 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
    

Remarque: Lorsque vous avez terminé le projet, remettez les contrôles d'accès à leur valeur par défaut - xhost -local:docker

Plus de détails: utilisation des interfaces graphiques avec Docker

Crédit: Détection d'objets en temps réel et de traitement vidéo à l'aide de Tensorflow, OpenCV et Docker


"Créer le socket Unix X11 et le fichier d'authentification X" ne crée pas de fichiers, il définit juste des variables?
MrR
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.