J'exécute un conteneur Docker principalement comme un environnement de développement isolé pour le langage R
. (L'utilisation de R
ici est orthogonale au reste de l'article, c'est-à-dire que vous pouvez simplement supposer que n'importe quel programme générique pouvant s'exécuter dans une session repl
-.) Souvent, cela impliquera faire des trucs comme tracer, faire des graphiques et ainsi de suite; et je dois les regarder. Par conséquent, je préférerais avoir la possibilité d'afficher les graphiques que j'ai créés dans mon conteneur. Voici comment je fais cela jusqu'à présent. Je crée d'abord un Dockerfile
. En laissant de côté les étapes triviales, les plus pertinentes sont:
# Set root passwd
RUN echo "root:test" | chpasswd
# Add user so that container does not run as root
RUN useradd -m docker
RUN echo "docker:test" | chpasswd
RUN usermod -s /bin/bash docker
RUN usermod -aG Sudo docker
ENV HOME /home/docker
RUN mkdir /var/run/sshd
RUN mkdir -p /var/log/supervisor
# copy servisord.conf which lists the processes to be spawned once this
# container is started (currently only one: sshd)
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
EXPOSE 22
CMD ["/usr/bin/supervisord"]
Je crée l'image puis démarre le conteneur en utilisant:
docker run -d -p 127.0.0.1:5000:22 -h ubuntu-r -v /home/chb/files/Data:/home/docker/Data -P --name="rdev" ubuntu-r
et peut ensuite ssh dans mon conteneur:
ssh -X docker@localhost -p 5000.
Cela me donnera ce que je veux. Mais je voudrais savoir s'il existe un autre moyen plus respectueux des ressources pour obtenir des sorties graphiques/GUI à partir d'un conteneur? (Je préférerais, si possible, que les solutions n'impliquent pas vnc
.)
Il existe un moyen agréable et semi-facile d'obtenir la sortie graphique d'un conteneur Docker sans avoir à exécuter un démon sshd
à l'intérieur du conteneur. Docker peut fournir des performances nues lors de l'exécution d'un seul processus qui dans ce cas est censé être R
. L'exécution d'un démon sshd, aussi marginale soit-elle, introduira une surcharge supplémentaire. Cela n'est pas amélioré en exécutant le démon sshd en tant que processus enfant du démon superviseur. Les deux peuvent être supprimés lorsque l'on fait bon usage des supports de reliure. Après avoir construit l'image à partir de laquelle le conteneur est censé être exécuté, nous démarrons un conteneur interactif et y lions le dossier /tmp/.X11-unix
. Je vais énoncer la commande complète et expliquer en détail ce qu'elle fait:
docker run -i -t --rm \
-i
Organise une session interactive; -t
Alloue un pseudo tty; --rm
Rend ce conteneur éphémère-e DISPLAY = $ DISPLAY \
:0
)-u docker \
-u
Spécifiez que le processus doit être exécuté par un utilisateur (ici docker
) et non par root. Cette étape est importante (v.i.)!-v /tmp/.X11-unix:/tmp/.X11-unix:ro \
-v
Monte le socket X11
Résidant dans /tmp/.X11-unix
Sur votre machine locale dans /tmp/.X11-unix
Dans le conteneur et :ro
Rend le socket en lecture seule .--name = "rdev" ubuntu-r R
--name=""
Spécifiez le nom du conteneur (ici rdev
); l'image à partir de laquelle vous souhaitez exécuter le conteneur (ici ubuntu-r
); le processus que vous souhaitez exécuter dans le conteneur (ici R
). (La dernière étape de spécification d'un processus n'est nécessaire que si vous n'avez pas défini un CMD
ou ENTRYPOINT
par défaut pour votre image.)Après avoir lancé cette commande, vous devriez regarder la belle sortie de démarrage R
. Si vous deviez essayer demo(graphics)
pour voir si la sortie graphique fonctionne déjà, vous remarquerez que ce n'est pas le cas. Cela est dû à l'extension Xsecurity
qui vous empêche d'accéder au socket. Vous pouvez maintenant taper xhost +
Sur votre machine locale et réessayer demo(graphics)
dans votre conteneur. Vous devriez maintenant avoir une sortie graphique. Cependant, cette méthode est fortement déconseillée car vous autorisez l'accès à votre xsocket à tout hôte distant auquel vous êtes actuellement connecté. Tant que vous n'interagissez qu'avec des systèmes à utilisateur unique, cela peut être justifié d'une manière ou d'une autre, mais dès qu'il y aura plusieurs utilisateurs impliqués, ce sera absolument dangereux! Par conséquent, vous devez utiliser une méthode moins dangereuse. Un bon moyen est d'utiliser le serveur interprété
xhost +si:localuser:username
qui peut être utilisé pour spécifier un seul utilisateur local (voir man xhost
). Cela signifie que username
doit être le nom de l'utilisateur qui exécute le serveur X11
Sur votre machine locale et qui exécute le conteneur Docker. C'est également la raison pour laquelle il est important de spécifier un utilisateur lors de l'exécution de votre conteneur. Enfin, il existe toujours la solution la plus complexe qui consiste à utiliser les fichiers xauth
et .Xauthority
Pour accorder l'accès à la socket X11
(Voir man xauth
). Cela impliquera cependant un peu plus de connaissances sur le fonctionnement de X
.
L'effet positif que cela peut avoir peut être vu dans le nombre de processus qui doivent être exécutés pour atteindre ce que l'on souhaite.
(1) avec supervisor
et sshd
s'exécutant dans le conteneur:
UID PID PPID C STIME TTY TIME CMD
root 4564 718 1 18:16 ? 00:00:00 /usr/bin/python /usr/bin/supervisord
root 4576 4564 0 18:16 ? 00:00:00 /usr/sbin/sshd
lorsque vous êtes connecté via ssh
et exécutez R
:
UID PID PPID C STIME TTY TIME CMD
root 4564 718 0 18:16 ? 00:00:00 /usr/bin/python /usr/bin/supervisord
root 4576 4564 0 18:16 ? 00:00:00 /usr/sbin/sshd
root 4674 4576 0 18:17 ? 00:00:00 sshd: docker [priv]
chb 4725 4674 0 18:18 ? 00:00:00 sshd: docker@pts/0
chb 4728 4725 1 18:18 pts/0 00:00:00 -bash
(2) avec la méthode de montage bind:
UID PID PPID C STIME TTY TIME CMD
chb 4356 718 0 18:12 pts/4 00:00:00 /usr/local/lib/R/bin/exec/R --no-save --no-restore
Voici clairement la meilleure solution que j'ai trouvée jusqu'à présent:
https://stackoverflow.com/a/25280523/13539 (tout le mérite revient à Jürgen Weigert)
Avantages:
xhost +
)