Чи можна запускати програми GUI в контейнері Docker?


409

Як можна запускати програми GUI в контейнері Docker ?

Чи є якісь зображення, які налаштовані, vncserverабо щось таке, що ви можете, наприклад, додати додаткову пісочну скриньку швидкості навколо, наприклад, Firefox?


Це питання стосується лише Linux (виходячи з віку та вмісту відповідей), а не Windows. Якщо так, чи можемо ми відредагувати заголовок, щоб уточнити це? Спасибі
UuDdLrLrSs


Перегляньте посібник користувача з HPC Visualization Containers для деяких ідей.
kenorb

Відповіді:


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:

Для Докер версії 18 або новішої:

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

Для Докер версії 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 +, здається, не працює.
користувач94154

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

9
зображення creackfirefox-vnc не вдається з помилкою: Введіть пароль VNC: stty: стандартний ввід: Невідповідний ioctl для файлів пристрою: Немає такого файлу чи каталогу stty: стандартний ввід: Невідповідний ioctl для пристрою x11vnc -usepw: не вдалося знайти пароль для використання.
alfonsodev

6
Добре використовуйте docker> Запуск програм GUI з Docker fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
Dennis C

7
Немає імені користувача, пароль чітко вказаний у відповіді, і будь-який клієнт vnc зробить. У моєму випадку мені подобається рідний osx. (з Finder, натисніть команду + K і підключіться до vnc: // <docker ip>: <порт відкритого контейнера>)
скрип

195

Xauthority стає проблемою з більш новими системами. Я можу зняти будь-який захист за допомогою xhost + перед тим, як запустити контейнери докера, або можу передати добре підготовлений файл Xauthority. Типові файли Xauthority залежать від імені хоста. За допомогою докера кожен контейнер може мати інше ім'я хоста (встановлений за допомогою докерного запуску -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
Петро Олександр Чмеловський

2
@PiotrAleksanderChmielowski, який не працював для мене, версія Docker 1.12.0, build 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 всередині контейнера докера не може прочитати файл. Ви можете перевірити, запустивши xauth listв контейнер докер. Я додав chmod 755 $XAUTHпісля xauth nlist :0 | ...команди, щоб вирішити цю проблему.
Абай

2
@Abai Навіщо використовувати 755, якщо 444 або 644 достатньо?
Даніель Альдер

68

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

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

PROS:
+ відсутність x серверних даних у контейнері docker
+ не потрібен клієнт / сервер vnc
+ відсутність ssh з x переадресацією
+ значно менші контейнери докера

CONS:
- використання 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 .

і команда run:

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

звичайно, ви також можете це зробити в команді run за допомогою sh -c "echo script-here"

Підказка: для аудіо дивіться: https://stackoverflow.com/a/28985715/2835523


Як це зробити на Windows 7? Чи потрібно мені встановити X-сервер?
walksignison

3
Оскільки більшість відповідей тут стосується лише Unix, я думаю - поки Windows не підтримує віконну систему X-сервера.
A. Binzxxxxxx

Як ви думаєте, це може спрацювати, якщо я встановив X-сервер на Windows або навіть вклав X-сервер у свій Docker-контейнер?
walksignison

1
Я думаю, вам також потрібно встановити в Dockerfile, apt-get -y install sudoщоб створити /etc/sudoers.dпапку.
mulg0r

1
також може знадобитися дозволити з'єднання з X від будь-якого хоста з$ xhost +
Bandoos

52

З томами даних докера дуже просто викрити розетку домену xorg 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. Він надає контейнеру повний доступ до xserver на хості, тому рекомендується лише якщо ви довіряєте тому, що знаходиться всередині.

Примітка. Якщо ви стурбовані безпекою, кращим рішенням буде обмежити програму обов'язковим контролем доступу або на основі ролі . Докер здобув досить гарну ізоляцію, але він був розроблений з іншою метою. Використовуйте AppArmor , SELinux або GrSecurity , які були розроблені для вирішення ваших проблем.


5
Вам також потрібно дозволити доступ до сервера X від інших хостів за допомогою такого інструменту, як xhost. Щоб повністю відкрити його, використовуйте xhost +хост.
Туллі

3
@ Тільки xhost +localпотрібно. ~/.XauthorityОднак було б краще зробити файл доступним у контейнері, щоб він міг пройти автентифікацію.
Aryeh Leib Taurog

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

4
Раніше це працювало досить добре для мене на ноутбуці Ubuntu 14.04 з докером 1.5 раніше; але зараз для мене не вдається Ubuntu 15.04, докер 1.6.2, з помилкою Can't open display: :0. Будь-які ідеї?
cboettig

6
Раніше я xhost +si:localuser:$USERдозволяв користувачеві запускати контейнер.
Нік Брін

26

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

Це дозволяє упакувати багато додатків gui в докер. Firefox та emacs пройшли перевірку. З Firefox webGL не працює. Хром взагалі не працює.

EDIT: Звук працює!

EDIT2: За час, коли я вперше опублікував це, підопічний користувач сильно прогресував. Зараз у мене є веб-сайт subuser.org та нова модель безпеки для підключення до X11 через мостику XPRA .


3
Зверніть увагу, що субпідрядник все ще дуже новий і відносно неперевірений. Якщо у вас виникли проблеми, надішліть звіти про помилки!
timthelion

Я б уникав X11, якщо є якийсь спосіб. У вашому додатку-вбивці буде запущений проксі-сервер у докері та запущений повний браузер із плагінами дочірнього докера, таким чином, що брандмауер та інше вимушує всю мережу через докер-тор. Це дозволить виконати кругообіг навколо поточного пакета браузерів Tor для зручності використання веб-сторінок, оскільки ви пропускаєте багатий вміст.
Буде чи

1
Чи у вас проблеми з безпекою X11? Або ви хочете, щоб це працювало з windows? Або ви хочете, щоб це працювало віддалено? Все вищеперераховане? Я думаю, що зробити цю роботу з vnc цілком можливо (хоча я не став би її методом за замовчуванням, оскільки це додає залежність від vnc). Здійснення віддаленої роботи субпідрядників насправді неможливо / має сенс. Існує також таке: github.com/rogaha/docker-desktop, але із звітів про помилки, здається, xpra може бути непридатним у реальному житті.
таймліон

24

OSX

Юрген Вейгерт має найкращу відповідь, яка працювала на мене на Ubuntu, однак на OSX, докер працює всередині VirtualBox, і тому рішення не працює без додаткової роботи.

У мене це працює з цими додатковими інгредієнтами:

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

Я вдячний коментарям користувачів, щоб поліпшити цю відповідь для OSX, я не впевнений, чи безпека переадресації сокета для X, але моє призначення призначене для запуску контейнера докера лише локально.

Крім того, сценарій трохи крихкий тим, що отримати 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 Віддалений доступ до повного
  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, коли докерські програми працюють на вкладеному X-сервері.
  • MIT-SHM вимкнено, щоб уникнути збоїв доступу до ОЗУ.
  • Безпека контейнерів покращується за допомогою --cap-drop ALL --security-opt no-new-privileges. Також користувач контейнера не має root.
  • Файл cookie X створений для обмеження доступу до дисплея Xephyr.

Сценарій очікує деяких аргументів: перший менеджер вікон хоста запускається в Xephyr, другий зображення докера, необов'язково третій команда зображення, яка буде виконана. Щоб запустити середовище робочого столу в docker, використовуйте ":" замість менеджера вікон хоста.

Закриття вікна Xephyr припиняє застосування контейнерів для докерів. Припинення докерованих додатків закриває вікно 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 . Більш просунутий сценарій - x11docker, який також підтримує такі функції, як прискорення графічного процесора, обмін веб-камерами та принтерами тощо.


18

Ось легке рішення, яке дозволяє уникнути встановлення будь-якого Xсервера, vncсервера чи sshdдемона на контейнері. Що отримує у простоті, воно втрачає у захисті та ізоляції.

Він передбачає, що ви підключаєтесь до хост-машини за sshдопомогою X11переадресації.

У sshdконфігурації хоста додайте рядок

X11UseLocalhost no

Так що пересилається порт сервера X на хості відкритий для всіх інтерфейсів (не тільки lo) і , зокрема , на віртуальному інтерфейсі Докер, 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-переадресацію ..)
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 і ~/.Xauthorityфайл в контейнер. Ці рішення часто працюють випадково, не розуміючи, чому, наприклад, користувач контейнера закінчується тим самим UID, що і користувач, тому немає необхідності в авторизації магічних ключів.

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

Навіть якщо ви скопіюєте файл у контейнер та зміните право власності, є ще одна проблема. Якщо ви працюєте xauth listна хості та контейнері, з одним і тим же Xauthorityфайлом, ви побачите в списку різні записи. Це тому, що xauthфільтрує записи залежно від місця її запуску.

Клієнт X у контейнері (тобто GUI-додаток) поводитиметься так само, як і xauth. Іншими словами, він не бачить чарівного файлу cookie для сесії X, що працює на робочому столі користувача. Натомість він бачить записи для всіх «віддалених» X сесій, які ви відкрили раніше (пояснено нижче).

Отже, що вам потрібно зробити, це додати новий запис із назвою хоста контейнера і тим же шістнадцятковим ключем, що і cookie хоста (тобто X сеанс, що працює на вашому робочому столі), наприклад:

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

Проблема полягає в тому, що файл cookie потрібно додати 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працює, чи якxauth або клієнти X фільтрують записи з файлу Xauthority залежно від місця їх запуску. Додаткова інформація щодо цього вітається.

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

Це також допомагає зрозуміти механіку процесу авторизації:

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

Примітка: Розетку X11 Unix все ще потрібно встановити в контейнері, інакше контейнер не матиме маршруту до сервера X. Більшість дистрибутивів за замовчуванням відключають доступ TCP до сервера X з міркувань безпеки.

Для отримання додаткової інформації та для кращого розуміння того, як працює взаємодія X клієнт / сервер, також корисно переглянути приклад випадку переадресації SSH X:

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

12

Це не мало ваги, але це приємне рішення, яке надає паритету функції докера повну віртуалізацію робочого столу. І Xfce4, або IceWM для Ubuntu і CentOS працюють, і цей noVNCваріант дозволяє легко отримати доступ через браузер.

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

Він працює noVNCтак само, як tigerVNCі vncserver 's. Потім він вимагає 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 допоможе вам у цьому.
toschneck

11

Рішення, подане на веб-сайті http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ , здається, простий спосіб запуску програм GUI зсередини контейнерів (я спробував Firefox над 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як гучності більше не працює, оскільки докер мовчки відмовляється від кріплення томів у липких каталогах.
Крістіан Худжер

1
Я думаю, це залежить від того, який дистрибутив ти використовуєш. Ви, безумовно, можете прив’язати гніздо X11 Unix на CentOS. Також важливо зрозуміти, що --network=hostробить. Це надає вашому контейнеру повний доступ до мережевого стека хоста, що може бути небажаним, залежно від того, що ви намагаєтеся зробити. Якщо ви просто розмовляєте із запуском контейнерних графічних інтерфейсів на робочому столі, це не має значення.
інструбхен

7

Існує ще одне рішення від lord.garbage для запуску програм GUI в контейнері без використання VNC, SSH та X11 переадресації. Він згадується тут теж.


1
Це чудово, якщо безпека не викликає побоювань. Якщо метою стикування чогось є його ізоляція, найкраще уникати потрапляння X11 з контейнера.
Буде чи

7

Якщо ви хочете запустити програму GUI без голови, прочитайте тут . Що вам потрібно зробити, це створити віртуальний монітор з xvfbіншим подібним програмним забезпеченням. Це дуже корисно, якщо ви хочете запустити тести Selenium, наприклад, із браузерами.

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


6

Я запізнився на вечірку, але для користувачів Mac , які не хочуть йти по шляху XQuartz, ось робочий приклад , який будує Fedora Image з Desktop Environment (XFCE) , використовуючи Xvfbі VNC. Це просто, і працює:

На Mac, ви можете просто отримати доступ до нього за допомогою програми « Спільний доступ до екрана (за замовчуванням)», підключившись до localhost:5901.

Докерфайл:

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 для складання та запуску команд, якщо ви хочете / потребуєте.


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

Під час перезавантаження системи, перед входом користувача, докер автоматично змонтує каталог $ 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 докер, а також надати користувачеві, який розпочав докер, доступ до 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, висока sierra)

Подібно до відповіді @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

Докер з мережею BRIDGE. для 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 без судо ( Як виправити докер: Отримано дозвіл відмовлено )

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

  3. папка dev для ліфтів, залежних від драйверів, для роботи

  4. плюс X11 вперед.

    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} id -u ${USER}--user = --env = "DISPLAY" --volume = "/ тощо / passwd: / etc / passwd: ro "-it REPO: TAG / bin / bash
user1145922

1

Мені вдалося запустити відео потік з камери USB , використовуючи opencvв dockerвиконавши наступні дії:

  1. Нехай докер отримує доступ до 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 на "рідну", щоб вона не обходила двигун візуалізації 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.