Можете ли вы запускать приложения с графическим интерфейсом в контейнере Docker?


409

Как вы можете запускать приложения с графическим интерфейсом в контейнере Docker ?

Есть ли какие-либо изображения, которые настроены vncserverили что-то такое, что вы можете - например - добавить дополнительную песочницу SpeedBump вокруг, скажем, Firefox?


Этот вопрос, похоже, относится только к Linux (в зависимости от возраста и содержания ответов), а не к Windows. Если да, можем ли мы отредактировать заголовок, чтобы уточнить это? Спасибо
UuDdLrLrSs


Ответы:


238

Вы можете просто установить vncserver вместе с Firefox :)

Я нажал изображение, VNC / Firefox, здесь: docker pull creack/firefox-vnc

Изображение было сделано с этим 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'

Это создаст контейнер Docker с VNC с паролем 1234:

Для Docker версии 18 или новее:

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

Для Docker версии 1.3 или новее:

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

Для Docker до версии 1.3:

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

2
Как бы я использовал VNC-клиент для удаленного просмотра? Ввод в порт IP +, кажется, не работает.
user94154

17
Во-первых, вам нужно проверить выделенный порт (выполнив docker inspect <container id>или просто docker ps, затем вы подключаетесь к ip вашего хоста с портом, который вы только что нашли.
creack

9
образ creackfirefox-vnc завершается с ошибкой: введите пароль VNC: stty: стандартный ввод: неподходящий ioctl для устройств fgets: такого файла или каталога нет: stty: стандартный ввод: неподходящий ioctl для устройства x11vnc -usepw: не удалось найти пароль для использования.
Альфонсодев

6
Хорошо используйте Docker> Запуск приложений с графическим интерфейсом с помощью Docker fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
Деннис C

7
Там нет имени пользователя, пароль четко указан в ответе и подойдет любой клиент vnc. В моем случае мне нравится родной OSX. (из поиска, нажмите команду + K и подключитесь к vnc: // <IP-
адрес

195

Xauthority становится проблемой с более новыми системами. Я могу либо отменить любую защиту с помощью xhost + перед запуском моих док-контейнеров, либо передать хорошо подготовленный файл Xauthority. Типичные файлы Xauthority зависят от имени хоста. С помощью docker каждый контейнер может иметь свое имя хоста (устанавливается с помощью команды docker run -h), но даже установка имени хоста контейнера, идентичного системе хоста, в моем случае не помогла. xeyes (мне нравится этот пример) просто игнорирует волшебный cookie и не передает учетные данные на сервер. Следовательно, мы получаем сообщение об ошибке «Протокол не указан. Не удается открыть дисплей»

Файл Xauthority может быть записан таким образом, чтобы имя хоста не имело значения. Нам нужно установить для семейства аутентификации значение «FamilyWild». Я не уверен, если xauth имеет подходящую командную строку для этого, так что вот пример, который комбинирует xauth и sed для этого. Нам нужно изменить первые 16 бит вывода nlist. Значение FamilyWild равно 65535 или 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
Просто примечание, -v $XSOCK:$XSOCK -v $XAUTH:$XAUTHможет быть сокращено до-v $XSOCK -v $XAUTH
Петр Александр Chmielowski

2
@PiotrAleksanderChmielowski, который не работал для меня, Docker версия 1.12.0, сборка 8eab29e
tbc0

14
@Dirk: вы можете заменить :0на $DISPLAY. Это значит xauth nlist $DISPLAY | ...и docker run -ti -e DISPLAY=$DISPLAY .... Обычно X DISPLAY есть :0, но не всегда (и особенно если вы подключаетесь через ssh -X).
Johndodo

4
На Ubuntu 16.04 xauth создает /tmp/.docker.xauthфайл с 600разрешениями. Это приводит к тому, что xauth внутри Docker-контейнера не может прочитать файл. Вы можете проверить, запустив xauth listв Docker контейнере. Я добавил chmod 755 $XAUTHпосле xauth nlist :0 | ...команды, чтобы решить эту проблему.
Абай

2
@Abai Зачем использовать 755, если 444 или 644 достаточно?
Даниэль Олдер

68

Я только что нашел эту запись в блоге и хочу поделиться ею здесь с вами, потому что я думаю, что это лучший способ сделать это, и это так просто.

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

ПЛЮСЫ:
+ не
требуется x сервер в контейнере Docker + не требуется клиент / сервер vnc
+ нет ssh с переадресацией x
+ гораздо меньшие док-контейнеры

МИНУСЫ:
- использование x на хосте (не предназначено для безопасной песочницы)

на случай, если ссылка когда-нибудь выйдет из строя, я поместил здесь самую важную часть:
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

построить изображение:

docker build -t firefox .

и команда запуска:

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

конечно, вы также можете сделать это в команде запуска с sh -c "echo script-here"

ПОДСКАЗКА: для аудио взгляните на: https://stackoverflow.com/a/28985715/2835523


Как я могу сделать это на Windows 7? Нужно ли устанавливать X-сервер?
прогулка

3
Как и большинство ответов здесь, это относится только к Unix, я думаю - до тех пор, пока Windows не поддерживает оконную систему X-сервера.
A. Binzxxxxxx

Как вы думаете, это может сработать, если я установлю X-сервер в Windows или даже добавлю X-сервер в свой контейнер Docker?
Walkingignison

1
Я думаю, что вам также нужно установить в Dockerfile, apt-get -y install sudoчтобы создать /etc/sudoers.dпапку.
mulg0r

1
может также понадобиться разрешить подключения к X с любого хоста с$ xhost +
Bandoos

52

С объемами данных докера очень легко вывести сокет домена xix unix внутри контейнера.

Например, с таким Dockerfile:

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

Вы можете сделать следующее:

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

Это, конечно, по сути то же самое, что и X-forwarding. Он предоставляет контейнеру полный доступ к xserver на хосте, поэтому рекомендуется, только если вы доверяете тому, что находится внутри.

Примечание. Если вы беспокоитесь о безопасности, лучшим решением было бы ограничить приложение обязательным или ролевым контролем доступа. Докер достигает довольно хорошей изоляции, но он был разработан с другой целью. Используйте AppArmor , SELinux или GrSecurity , которые были разработаны для решения вашей проблемы.


5
Вам также необходимо разрешить доступ к X-серверу с других хостов с помощью такого инструмента, как xhost. Чтобы полностью открыть его используйте xhost +на хосте.
Талли,

3
@ Только xhost +localнеобходимо. Однако было бы лучше сделать ~/.Xauthorityфайл доступным в контейнере, чтобы он мог аутентифицировать себя.
Арье Лейб Таурог

3
Вам удалось заставить его работать на Mac (используя boot2docker)?
Карл Форнер

4
Это работало довольно хорошо для меня на ноутбуке Ubuntu 14.04 с докером 1.5 ранее; но сейчас происходит сбой для меня на Ubuntu 15.04, Docker 1.6.2, с ошибкой Can't open display: :0. Любые идеи?
cboettig

6
Раньше я xhost +si:localuser:$USERавторизовал только пользователя, запускающего контейнер.
Ник Брин

26

Вы также можете использовать подпользователя: https://github.com/timthelion/subuser

Это позволяет вам упаковать много приложений графического интерфейса в докер. Firefox и emacs были протестированы до сих пор. С Firefox WebGL не работает, хотя. Хром не работает вообще.

РЕДАКТИРОВАТЬ: Звук работает!

РЕДАКТИРОВАТЬ 2: С тех пор, как я впервые опубликовал это, subuser значительно прогрессировал. Теперь у меня есть веб-сайт subuser.org и новая модель безопасности для подключения к X11 через мост XPRA .


3
Обратите внимание, что subuser все еще очень новый и относительно не проверенный. Если у вас возникнут какие-либо проблемы, отправляйте сообщения об ошибках!
тимтелион

Я бы избежал X11, если есть возможность. Ваше приложение-убийца будет запускать прокси-сервер tor в докере и запускать полный браузер с плагинами в дочернем докере, так что брандмауэр и т. Д. Вынуждает всю сеть выходить через док-станцию ​​tor. Это будет обходить текущий комплект браузеров для удобства использования в Интернете, потому что вы пропустите богатый контент.
Будет

1
Проблемы с безопасностью X11? Или вы хотите, чтобы это работало с окнами? Или вы хотите, чтобы это работало удаленно? Все вышеперечисленное? Я думаю, что сделать это с помощью vnc вполне возможно (хотя я бы не стал использовать этот метод по умолчанию, поскольку он добавляет зависимость от vnc). Заставить работать подпользователя удаленно не реально / не имеет смысла. Существует также следующее: github.com/rogaha/docker-desktop, но из сообщений об ошибках кажется, что xpra может быть непригодным для использования в реальной жизни.
тимтелион

24

OSX

У Юргена Вайгерта есть лучший ответ, который работал для меня в Ubuntu, однако в OSX докер работает внутри VirtualBox, поэтому решение не работает без дополнительной работы.

У меня это работает с этими дополнительными ингредиентами:

  1. Xquartz (OSX больше не поставляется с сервером X11)
  2. переадресация сокетов с помощью socat (brew install socat)
  3. bash скрипт для запуска контейнера

Я был бы признателен за комментарии пользователей, чтобы улучшить этот ответ для OSX, но я не уверен, что переадресация сокетов для X безопасна, но я предполагаю использовать его только для запуска контейнера Docker локально.

Кроме того, сценарий немного хрупок в том смысле, что нелегко получить IP-адрес компьютера, поскольку он находится на нашей локальной беспроводной сети, поэтому всегда есть какой-то случайный IP-адрес.

Сценарий BASH, который я использую для запуска контейнера:

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

Я могу заставить xeyes и matplotlib работать с этим подходом.

Windows 7+

В Windows 7+ с MobaXterm это немного проще:

  1. Установите MobaXterm для Windows
  2. Запустите MobaXterm
  3. Настройка X-сервера: Настройки -> X11 (вкладка) -> установить X11 Remote Access на полный
  4. Используйте этот BASH-скрипт для запуска контейнера

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 работает на ПК


я не понял, что вы имели в виду под сценарием bash - как мне запустить его в windows?
Деллер

@deller Я занимаюсь разработкой программного обеспечения для Windows с использованием GIT, поэтому у меня есть оболочка GIT-bash.
Ник

Я следовал за шагами. Тем не менее, я получаю error: XDG_RUNTIME_DIR not set in the environment.и Error: cannot open display: VAIO:0.0. Вы сталкивались с чем-то вроде этого?
user3275095

1
Я получаю ошибку, связанную с тем, что пользователь не найден, т.е. "нет подходящих записей в файле passwd".
Walksignison

19

Совместное использование дисплея хоста: 0, как указано в некоторых других ответах, имеет два недостатка:

  • Это нарушает изоляцию контейнера из-за некоторых утечек безопасности X. Например, кейлогинг с xevили xinputвозможно, и удаленное управление хост-приложениями сxdotool .
  • Приложения могут иметь сбои рендеринга и плохие ошибки доступа к ОЗУ из-за отсутствия общей памяти для расширения X MIT-SHM. (Также может быть исправлено с помощью опции, ухудшающей изоляцию --ipc=host).

Ниже приведен пример сценария для запуска образа докера в Xephyr, который решает эту проблему.

  • Это позволяет избежать утечек безопасности X, так как приложения Docker работают на вложенном X-сервере.
  • MIT-SHM отключен, чтобы избежать ошибок доступа к ОЗУ.
  • Безопасность контейнеров улучшена с --cap-drop ALL --security-opt no-new-privileges. Также пользователь контейнера не является пользователем root.
  • X cookie создается для ограничения доступа к отображению Xephyr.

Скрипт ожидает некоторых аргументов: сначала менеджер окон хоста будет запущен в Xephyr, второй образ докера, опционально третья команда образа, которая будет выполнена. Чтобы запустить среду рабочего стола в Docker, используйте «:» вместо менеджера окон хоста.

Закрытие окна Xephyr завершает работу приложений Docker-контейнера. Завершение закрепленных приложений закрывает окно Xephyr.

Примеры:

  • xephyrdocker "openbox --sm-disable" x11docker/lxde pcmanfm
  • xephyrdocker : x11docker/lxde
  • xephyrdocker xfwm4 --device /dev/snd jess/nes /games/zelda.rom

Скрипт 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

Этот скрипт поддерживается на x11docker wiki . Более продвинутый скрипт - x11docker, который также поддерживает такие функции, как ускорение графического процессора, совместное использование веб-камеры и принтера и так далее.


18

Вот упрощенное решение, которое позволяет избежать необходимости устанавливать на Xсервере любой сервер, vncсервер или sshdдемон. То, что он получает в простоте, он теряет в безопасности и изоляции.

Предполагается, что вы подключаетесь к хост-машине с sshпомощьюX11 переадресации.

В sshdнастройках хоста добавьте строку

X11UseLocalhost no

Так что перенаправленный порт X-сервера на хосте открыт на всех интерфейсах (не только lo) и, в частности, на виртуальном интерфейсе Docker docker0.

Контейнеру при запуске необходим доступ к .Xauthorityфайлу, чтобы он мог подключиться к серверу. Чтобы сделать это, мы определяем том только для чтения, указывающий на домашний каталог на хосте (возможно, не мудрая идея!), И также устанавливаем XAUTHORITYпеременную соответственно.

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

Этого недостаточно, мы также должны передать переменную DISPLAY от хоста, но подставив имя хоста ip:

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

Мы можем определить псевдоним:

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

И проверить это так:

dockerX11run centos xeyes

2
(Это отлично подходит для надежных приложений. Тем не менее, для любого вида песочницы вы должны избегать X-forwarding.)
Will

1
Если вы не хотите устанавливать весь домашний каталог в контейнер , вы можете просто установить .Xauthorityсам файл: -v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority.
Роберт Хейнс

2
Вместо изменения X11UseLocalhostвы также можете использовать дополнительную опцию --net=hostдля docker runкоманды (см. Здесь ).
ingomueller.net

--net=hostэто плохая идея, так как теперь, если вы откроете порт в контейнере, он будет открыт и в хосте ...
MrR

16

Хотя ответ Юргена Вайгерта, по сути, охватывает это решение, мне сначала было не ясно, что там описывалось. Поэтому я добавлю свою точку зрения на случай, если кому-то еще понадобятся разъяснения.

Прежде всего, соответствующей документацией является X-страница безопасности .

Многочисленные источники в Интернете предлагают просто смонтировать сокет X11 unix и ~/.Xauthorityфайл в контейнер. Эти решения часто работают на счастье, не понимая, почему, например, пользователь контейнера получает тот же UID, что и пользователь, поэтому нет необходимости в авторизации с помощью магического ключа.

Прежде всего, файл Xauthority имеет режим 0600, поэтому пользователь контейнера не сможет прочитать его, если у него не будет того же UID.

Даже если вы скопируете файл в контейнер и измените владельца, существует еще одна проблема. Если вы работаете xauth listна хосте и контейнере с одним и тем же Xauthorityфайлом, вы увидите разные записи в списке. Это потому, что xauthфильтрует записи в зависимости от того, где он запущен.

X-клиент в контейнере (т.е. приложение с графическим интерфейсом) будет вести себя так же, как xauth. Другими словами, он не видит магический файл cookie для сеанса X, запущенного на рабочем столе пользователя. Вместо этого он видит записи для всех «удаленных» сеансов X, которые вы открывали ранее (объяснено ниже).

Итак, вам нужно добавить новую запись с именем хоста контейнера и тем же шестнадцатеричным ключом, что и файл cookie хоста (т. Е. Сеанс X, запущенный на вашем рабочем столе), например:

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

Уловка в том, что печенье должно быть добавлено xauth addвнутри контейнера:

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

В противном случае xauthпометьте его так, чтобы оно было видно только вне контейнера.

Формат этой команды:

xauth add hostname/$DISPLAY protocol hexkey

Где .представляет MIT-MAGIC-COOKIE-1протокол.

Примечание. Нет необходимости копировать или связывать-монтировать .Xauthorityв контейнер. Просто создайте пустой файл, как показано, и добавьте cookie.

Ответ Юргена Вайгерта обходит это, используя FamilyWildтип соединения, чтобы создать новый файл полномочий на хосте и скопировать его в контейнер. Обратите внимание, что сначала извлекается шестнадцатеричный ключ для текущего сеанса X из ~/.Xauthorityиспользования xauth nlist.

Итак, основные шаги:

  • Извлеките шестнадцатеричный ключ файла cookie для текущего сеанса X пользователя.
  • Создайте новый файл Xauthority в контейнере с именем хоста контейнера и общим шестнадцатеричным ключом (или создайте cookie-файл с FamilyWildтипом соединения).

Я признаю, что не очень хорошо понимаю, как FamilyWildработает или как xauthX-клиенты фильтруют записи из файла Xauthority в зависимости от того, где они запускаются. Дополнительная информация об этом приветствуется.

Если вы хотите распространять свое приложение Docker, вам понадобится стартовый скрипт для запуска контейнера, который получает шестнадцатеричный ключ для сеанса X пользователя и импортирует его в контейнер одним из двух способов, описанных ранее.

Это также помогает понять механизм авторизации:

  • Клиент X (т.е. приложение с графическим интерфейсом), работающее в контейнере, ищет в файле Xauthority запись cookie, которая соответствует имени хоста контейнера и значению $DISPLAY.
  • Если соответствующая запись найдена, X-клиент передает ее с запросом авторизации на X-сервер через соответствующий сокет в /tmp/.X11-unixкаталоге, смонтированном в контейнере.

Примечание . Сокет Unix X11 по-прежнему необходимо монтировать в контейнере, иначе у контейнера не будет маршрута к X-серверу. Большинство дистрибутивов по умолчанию отключают доступ TCP к X-серверу.

Для получения дополнительной информации и лучшего понимания того, как работают отношения X клиент / сервер, полезно также рассмотреть пример пересылки SSH X:

  • Сервер SSH, работающий на удаленной машине, эмулирует свой собственный X-сервер.
  • Он устанавливает значение $DISPLAYв сеансе SSH для указания на свой собственный X-сервер.
  • Он используется xauthдля создания нового файла cookie для удаленного хоста и добавляет его в Xauthorityфайлы как для локальных, так и для удаленных пользователей.
  • Когда приложения с графическим интерфейсом запускаются, они общаются с эмулированным X-сервером SSH.
  • Сервер SSH пересылает эти данные обратно клиенту SSH на локальном рабочем столе.
  • Локальный SSH-клиент отправляет данные в сеанс X-сервера, запущенный на вашем рабочем столе, как если бы SSH-клиент был на самом деле X-клиентом (т. Е. Приложением с графическим интерфейсом).
  • X-сервер использует полученные данные для визуализации графического интерфейса на вашем рабочем столе.
  • В начале этого обмена удаленный X-клиент также отправляет запрос авторизации, используя только что созданный файл cookie. Локальный X-сервер сравнивает его с локальной копией.

12

Это не просто, но это хорошее решение, которое обеспечивает паритет функциональности докера с полной виртуализацией рабочего стола. Оба Xfce4 или IceWM для Ubuntu и CentOS работают, и эта noVNCопция обеспечивает легкий доступ через браузер.

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

Он работает noVNCтак же, как tigerVNCи vncserver. Затем он вызывает startxданный оконный менеджер. Кроме того, libnss_wrapper.soиспользуется для эмуляции управления паролями для пользователей.


кто-нибудь проверял это?
guilhermecgs

3
@guilhermecgs да, и отлично работает. С тех пор я также попробовал xpraв докере, который является безруковым X. Он xpraлучше всего подходил для IMO и более эффективен, чем VNC.
Дашесы

Просто чтобы прояснить ... Могу ли я иметь полный рабочий стол (GNOME, KDE) с этим изображением?
guilhermecgs

Я только попробовал Xfce4 и IceWM (который находится в этом репо). Конечно, опыт будет ограничен, например, монтирование устройств не будет отображаться на рабочем столе (gvfs), если вы не перейдете --device /dev/...к докеру и не установите необходимые --capпривилегии. Это побеждает цель сдерживания, но вы можете пройти через устройства. С некоторой настройкой должно быть возможно запустить GNOME / KDE под VNC. Я запустил несколько X в докере с картами NVIDIA (без VNC или Xpra), так что это, безусловно, выполнимо.
Дашесы

Мы не пробовали это до сих пор. Самой большой проблемой для этого было бы запустить работающего демона D-Bus. Большинству рабочих столов gnome или KDE они понадобятся. Пусть вам поможет проект ubuntu-desktop-lxde-vnc .
Тошнек

11

Решение, приведенное по адресу http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ , похоже, является простым способом запуска приложений с графическим интерфейсом изнутри контейнеров (я пробовал использовать Firefox over Ubuntu 14.04), но я обнаружил, что небольшое изменение требуется для решения, опубликованного автором.

В частности, для запуска контейнера автор упомянул:

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

Но я обнаружил, что (на основе конкретного комментария на том же сайте), что два дополнительных варианта

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

а также

    -net=host 

необходимо указать при запуске контейнера для корректной работы firefox:

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

Я создал образ докера с информацией на этой странице и этими дополнительными данными: https://hub.docker.com/r/amanral/ubuntu-firefox/


3
Я обнаружил, что вам даже не нужно пропускать /tmp/.X11-unixсокет вообще. Просто работает с креплением .Xauthorityи --net=host.
CMCDragonkai

2
На самом деле это единственное решение, которое работает в наши дни. Использование /tmp/.X11-unixтома больше не работает, так как Docker молча отказывается от монтирования тома из липких каталогов.
Кристиан Худжер

1
Я думаю, это зависит от того, какой дистрибутив вы используете. Вы определенно можете подключить Unix-разъем X11 на CentOS. Также важно понимать, что --network=hostделает. Это дает вашему контейнеру полный доступ к сетевому стеку хоста, что может быть нежелательно, в зависимости от того, что вы пытаетесь сделать. Если вы просто возитесь с запуском контейнерных графических интерфейсов на рабочем столе, то это не должно иметь значения.
Ордбен

7

Lord.garbage предлагает другое решение для запуска приложений с графическим интерфейсом в контейнере без использования перенаправления VNC, SSH и X11. Здесь тоже упоминается .


1
Это замечательно, если безопасность не является проблемой. Если целью стыковки чего-либо является его изоляция, лучше избегать попадания X11 из контейнера.
Будет

7

Если вы хотите запустить приложение с графическим интерфейсом без головы, тогда читайте здесь . Что вам нужно сделать, это создать виртуальный монитор с помощью xvfbили другого подобного программного обеспечения. Это очень полезно, если вы хотите запускать тесты Selenium, например, в браузерах.

Что-то нигде не упоминается, это то, что некоторые программы на самом деле сами используют песочницу с контейнерами Linux. Так, например, Chrome никогда не будет работать нормально, если вы не используете соответствующий флаг --privilegedпри запуске контейнера.


6

Я опаздываю на вечеринку, но для пользователей Mac, которые не хотят идти по пути XQuartz, вот рабочий пример, который создает образ Fedora с использованием среды рабочего стола (xfce) Xvfbи VNC. Все просто и работает:

На Mac вы можете просто получить к нему доступ, используя приложение Screen Sharing (по умолчанию), подключившись к 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

Проверьте связанный readme для команд build и run, если хотите / нуждаетесь.


5

Исходя из ответа Юргена Вейгерта , у меня есть некоторые улучшения:

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

Единственное отличие состоит в том, что он создает каталог $ XAUTH_DIR, который используется для размещения файла $ XAUTH и монтирования каталога $ XAUTH_DIR вместо файла $ XAUTH в док-контейнер.

Преимущество этого метода заключается в том, что вы можете написать команду в /etc/rc.local, которая должна создать пустую папку с именем $ XAUTH_DIR в / tmp и изменить ее режим на 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

При перезапуске системы перед входом пользователя docker автоматически монтирует каталог $ XAUTH_DIR, если политика перезапуска контейнера «всегда». После входа в систему вы можете написать в ~ / .profile команду для создания файла $ XAUTH, тогда контейнер автоматически использует этот файл $ 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

В конце концов, контейнер будет автоматически получать файл Xauthority при каждом перезапуске системы и входе пользователя в систему.


4

Другие решения должны работать, но вот решение для docker-compose.

Чтобы исправить эту ошибку, вам нужно передать $ DISPLAY и .X11-unix в Docker, а также предоставить пользователю, запустившему Docker, доступ к xhost.

Внутри docker-compose.ymlфайла:

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

В терминале или скрипте:

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


3

Вы можете разрешить пользователю Docker (здесь: root) доступ к дисплею 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, высокая Сьерра)

Похоже на ответ @Nick , но его решение у меня не сработало.

Сначала установите socat brew install socatи установите XQuartz ( https://www.xquartz.org/ ).

Затем выполните следующие действия здесь ( http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ ) в разделе комментариев:

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

Я также смог запустить CLion из моего докерского контейнера Debian.


1

Докер с сетью МОСТ. для Ubuntu 16.04 с менеджером отображения lightdm:

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

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

Вы можете использовать больше личных разрешений

xhost +

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

1

Еще один ответ, если вы уже создали изображение:

  1. вызвать docker без sudo ( Как исправить docker: проблема с запрещенным доступом )

  2. использовать один и тот же пользователь USER и home & passwd для общего ресурса хоста и контейнера (советы: используйте имя пользователя вместо имени пользователя)

  3. папка dev для зависимых от драйвера библиотек для правильной работы

  4. плюс Х11 вперед.

    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

Вы можете спросить, какой смысл использовать докер, если так много всего одинакового? хорошо, одна причина, о которой я могу думать, состоит в том, чтобы преодолеть ад зависимости пакета ( https://en.wikipedia.org/wiki/Dependency_hell ).

Так что этот тип использования больше подходит для разработчика, я думаю.


Это единственный, который будет работать для меня. В моих целях я смог свести это к минимуму: docker run --network = host --volume = echo ~: / home / $ {USER} --user = id -u ${USER}--env = "DISPLAY" --volume = "/ etc / passwd: / etc / passwd: ro "-it РЕПО: TAG / bin / bash
user1145922

1

Мне удалось запустить видео поток из камеры USB , используя opencvв dockerвыполнив следующие действия:

  1. Разрешить Docker доступ к X-серверу

    xhost +local:docker
    
  2. Создайте сокет X11 Unix и файл аутентификации X

    XSOCK=/tmp/.X11-unix
    XAUTH=/tmp/.docker.xauth
    
  3. Добавьте правильные разрешения

    xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
    
  4. Установите скорость рендеринга Qt на "native", чтобы она не обходила движок рендеринга X11

    export QT_GRAPHICSSYSTEM=native
    
  5. Скажите Qt не использовать MIT-SHM (разделяемая память) - таким образом, это также должно быть безопаснее с точки зрения безопасности

    export QT_X11_NO_MITSHM=1
    
  6. Обновите команду запуска докера

    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
    

Примечание. По завершении проекта верните элементы управления доступом по умолчанию. xhost -local:docker

Подробнее: использование графического интерфейса с Docker

Кредит: обнаружение объектов в режиме реального времени и обработки видео с использованием Tensorflow, OpenCV и Docker.


«Создать сокет X11 Unix и файл аутентификации X» не создает никаких файлов, он просто определяет переменные?
MrR
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.