Wie können Sie GUI-Anwendungen in einem Linux Docker-Container ausführen?
Gibt es Abbilder, die vncserver
oder ähnliches einrichten, so dass Sie - zum Beispiel - eine zusätzliche Sicherheitsbarriere um beispielsweise Firefox hinzufügen können?
Wie können Sie GUI-Anwendungen in einem Linux Docker-Container ausführen?
Gibt es Abbilder, die vncserver
oder ähnliches einrichten, so dass Sie - zum Beispiel - eine zusätzliche Sicherheitsbarriere um beispielsweise Firefox hinzufügen können?
Jürgen Weigert hat die beste Antwort, die für mich auf Ubuntu funktioniert hat. Auf OSX läuft Docker jedoch innerhalb von VirtualBox, sodass die Lösung ohne zusätzliche Arbeit nicht funktioniert.
Ich habe es mit diesen zusätzlichen Zutaten zum Laufen gebracht:
Ich würde Benutzerkommentare zur Verbesserung dieser Antwort für OSX begrüßen. Ich bin mir nicht sicher, ob die Socket-Weiterleitung für X sicher ist, aber ich beabsichtige sie nur lokal für das Ausführen des Docker-Containers zu verwenden.
Außerdem ist das Skript ein wenig fragil, da es nicht einfach ist, die IP-Adresse des Geräts abzurufen, da es in unserem lokalen Funknetz ist und daher immer eine zufällige IP ist.
Das BASH-Skript, das ich zum Starten des Containers verwende:
#!/usr/bin/env bash
CONTAINER=py3:2016-03-23-rc3
COMMAND=/bin/bash
NIC=en0
# Greifen Sie auf die IP-Adresse dieses Geräts zu
IPADDR=$(ifconfig $NIC | grep "inet " | awk '{print $2}')
DISP_NUM=$(jot -r 1 100 200) # zufällige Anzeigenummer zwischen 100 und 200
PORT_NUM=$((6000 + DISP_NUM)) # damit mehrere Instanzen des Containers sich nicht gegenseitig stören
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 # beenden Sie den oben gestarteten socat-Job
Mit diesem Ansatz kann ich xeyes und matplotlib zum Laufen bringen.
Auf Windows 7+ ist es mit MobaXterm etwas einfacher:
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
Das Anzeigen des Hosts mit :0 hat, wie in einigen anderen Antworten angegeben, zwei Nachteile:
xev
oder xinput
möglich, sowie die Fernsteuerung von Host-Anwendungen mit xdotool
.--ipc=host
behoben werden).Hier ist ein Beispiel-Skript, um ein Docker-Image in Xephyr auszuführen, das sich mit diesen Problemen befasst.
--cap-drop ALL --security-opt no-new-privileges
verbessert. Außerdem ist der Container-Benutzer nicht root.Das Skript erwartet einige Argumente, erstens einen Host-Fenster-Manager, der in Xephyr ausgeführt werden soll, zweitens ein Docker-Image und optional drittens einen Befehl, der ausgeführt werden soll. Um eine Desktop-Umgebung in Docker auszuführen, verwenden Sie ":" anstelle eines Host-Fenster-Managers.
Das Schließen des Xephyr-Fensters beendet die Docker-Containeranwendungen. Das Beenden der dockerisierten Anwendungen schließt das Xephyr-Fenster.
Beispiele:
xephyrdocker "openbox --sm-disable" x11docker/lxde pcmanfm
xephyrdocker : x11docker/lxde
xephyrdocker xfwm4 --device /dev/snd jess/nes /games/zelda.rom
xephyrdocker-Skript:
#! /bin/bash
#
# Xephyrdocker: Beispiel-Skript zum Ausführen von Docker-GUI-Anwendungen in Xephyr.
#
# Verwendung:
# Xephyrdocker FENSTERMANAGER DOCKERIMAGE [IMAGECOMMAND [ARGS]]
#
# FENSTERMANAGER Host-Fenster-Manager für die Verwendung mit einzelnen GUI-Anwendungen.
# Verwenden Sie ":" um ohne Fenster-Manager vom Host auszuführen
# DOCKERIMAGE Docker-Image mit GUI-Anwendungen oder einem Desktop
# IMAGECOMMAND Befehl zum Ausführen im Image
#
Fenstermanager="$1" && shift
Dockerimage="$*"
... (rest of the translation skipped for brevity) ...
Dieses Skript wird auf der x11docker-Wiki gepflegt. Ein fortschrittlicheres Skript ist x11docker, das auch Funktionen wie GPU-Beschleunigung, Webcam- und Druckerfreigabe und so weiter unterstützt.
Hier ist eine leichte Lösung, die es vermeidet, einen X
-Server, einen vnc
-Server oder einen sshd
-Daemon im Container installieren zu müssen. Was sie an Einfachheit gewinnt, verliert sie an Sicherheit und Isolation.
Es wird angenommen, dass Sie sich über ssh
mit X11
-Weiterleitung mit dem Host verbinden.
In der sshd
-Konfiguration des Hosts fügen Sie die Zeile hinzu
X11UseLocalhost nein
So wird der weitergeleitete X-Server-Port auf dem Host auf allen Schnittstellen geöffnet (nicht nur auf lo
) und insbesondere auf der Docker-Virtual-Schnittstelle, docker0
.
Der Container benötigt beim Ausführen Zugriff auf die Datei .Xauthority
, damit er sich mit dem Server verbinden kann. Dazu definieren wir ein schreibgeschütztes Volume, das auf das Home-Verzeichnis auf dem Host zeigt (vielleicht keine kluge Idee!) und setzen auch die Variable XAUTHORITY
entsprechend.
docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority
Das reicht nicht aus, wir müssen auch die DISPLAY-Variable vom Host übergeben, aber dabei den Hostnamen durch die IP ersetzen:
-e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")
Wir können ein Alias definieren:
alias dockerX11run='docker run -v $HOME:/hosthome:ro -e XAUTHORITY=/hosthome/.Xauthority -e DISPLAY=$(echo $DISPLAY | sed "s/^.*:/$(hostname -i):/")'
Und es wie folgt testen:
dockerX11run centos xeyes
Während die Antwort von Jürgen Weigert im Wesentlichen diese Lösung abdeckt, war es mir anfangs nicht klar, was dort beschrieben wurde. Deshalb werde ich meine Sichtweise dazu ergänzen, falls jemand anderes eine Erklärung braucht.
Zunächst einmal ist die relevante Dokumentation die X-Sicherheitsmanpage.
Zahlreiche Online-Quellen schlagen lediglich vor, den X11 Unix-Socket und die ~/.Xauthority
-Datei in den Container zu mounten. Diese Lösungen funktionieren oft durch Glück, ohne wirklich zu verstehen warum, z.B. der Container-Benutzer hat die gleiche UID wie der Benutzer, also gibt es keine Notwendigkeit für eine magische Schlüsselautorisation.
Zunächst einmal hat die Xauthority-Datei Modus 0600, sodass der Container-Benutzer sie nicht lesen kann, es sei denn, er hat die gleiche UID.
Auch wenn Sie die Datei in den Container kopieren und den Besitz ändern, gibt es immer noch ein anderes Problem. Wenn Sie xauth list
auf dem Host und Container ausführen, mit derselben Xauthority
-Datei, werden unterschiedliche Einträge aufgelistet. Das liegt daran, dass xauth
die Einträge filtert, je nachdem wo es ausgeführt wird.
Der X-Client im Container (d.h. die GUI-App) wird sich genauso wie xauth
verhalten. Mit anderen Worten sieht er nicht den magischen Cookie für die X-Sitzung, die auf dem Desktop des Benutzers läuft. Stattdessen sieht er die Einträge für alle "remote" X-Sitzungen, die Sie zuvor geöffnet haben (unten erklärt).
Also, was Sie tun müssen, ist einen neuen Eintrag mit dem Hostnamen des Containers und demselben Hex-Schlüssel wie der Host-Cookie (d.h. die X-Sitzung, die auf Ihrem Desktop läuft) hinzuzufügen, z.B.:
containerhostname/unix:0 MIT-MAGIC-COOKIE-1
Der Haken ist, dass der Cookie mit xauth add
im Container hinzugefügt werden muss:
touch ~/.Xauthority
xauth add containerhostname/unix:0 .
Andernfalls markiert xauth
ihn so, dass er nur außerhalb des Containers sichtbar ist.
Das Format für diesen Befehl ist:
xauth add hostname/$DISPLAY protocol hexkey
Wo .
das MIT-MAGIC-COOKIE-1
-Protokoll repräsentiert.
Hinweis: Es ist nicht notwendig, .Xauthority
in den Container zu kopieren oder zu binden. Einfach eine leere Datei erstellen, wie gezeigt, und den Cookie hinzufügen.
Die Antwort von Jürgen Weigert umgeht dies, indem er den Anschlusstyp FamilyWild
verwendet, um eine neue Autorisierungsdatei auf dem Host zu erstellen und sie in den Container zu kopieren. Beachten Sie, dass er zuerst den Hex-Schlüssel für die aktuelle X-Sitzung des Benutzers aus ~/.Xauthority
extrahiert, indem er xauth nlist
verwendet.
Die wesentlichen Schritte sind also:
FamilyWild
).Ich gebe zu, dass ich nicht sehr gut verstehe, wie FamilyWild
funktioniert oder wie xauth
oder X-Clients Einträge von der Xauthority-Datei filtern, je nachdem wo sie ausgeführt werden. Zusätzliche Informationen dazu sind willkommen.
Wenn Sie Ihre Docker-App verteilen möchten, benötigen Sie ein Startskript, um den Container auszuführen, das den Hex-Schlüssel für die X-Sitzung des Benutzers abruft und ihn auf eine der beiden zuvor erklärten Arten in den Container importiert.
Es hilft auch, den Mechanismus des Autorisierungsprozesses zu verstehen:
$DISPLAY
entspricht./tmp/.X11-unix
, das im Container gemountet ist.Hinweis: Der X11-Unix-Socket muss weiterhin im Container gemountet sein, ansonsten hat der Container keine Verbindung zum X-Server. Die meisten Distributionen deaktivieren den TCP-Zugriff auf den X-Server standardmäßig aus Sicherheitsgründen.
Für zusätzliche Informationen und ein besseres Verständnis, wie das X-Client/Server-Verhältnis funktioniert, ist es auch hilfreich, sich den Beispiel-Fall des SSH-X-Forwardings anzusehen:
$DISPLAY
in der SSH-Sitzung so, dass er auf seinen eigenen X-Server zeigt.xauth
, um ein neues Cookie für den Remote-Host zu erstellen, und fügt es den Xauthority
-Dateien für beide lokalen und entfernten Benutzer hinzu.Die Lösung auf http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ scheint tatsächlich ein einfacher Weg zu sein, um GUI-Anwendungen von innerhalb der Container zu starten (Ich habe es mit Firefox über Ubuntu 14.04 ausprobiert), aber ich habe festgestellt, dass eine kleine zusätzliche Änderung an der Lösung des Autors erforderlich ist.
Speziell für das Ausführen des Containers hat der Autor erwähnt:
docker run -ti --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
firefox
Ich habe jedoch festgestellt (basierend auf einem bestimmten Kommentar auf derselben Seite), dass zwei zusätzliche Optionen
-v $HOME/.Xauthority:$HOME/.Xauthority
und
-net=host
angegeben werden müssen, während der Container für Firefox ordnungsgemäß ausgeführt wird:
docker run -ti --rm \
-e DISPLAY=$DISPLAY \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v $HOME/.Xauthority:$HOME/.Xauthority \
-net=host \
firefox
Ich habe ein Docker-Image mit den Informationen auf dieser Seite und diesen zusätzlichen Erkenntnissen erstellt: https://hub.docker.com/r/amanral/ubuntu-firefox/
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.