Можете ли вы запускать приложения с графическим интерфейсом в Docker-контейнере?
Как вы можете запускать приложения с графическим интерфейсом в контейнере Docker?
Есть ли изображения, которые настроены vncserver
или что-то такое, что вы можете, например, добавить дополнительную песочницу SpeedBump вокруг, скажем, Firefox?
24 ответа
Вы можете просто установить 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 версии 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
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
Я только что нашел эту запись в блоге и хочу поделиться ею здесь с вами, потому что я думаю, что это лучший способ сделать это, и это так просто.
http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/
ПЛЮСЫ:
+ нет х серверного материала в 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"
ПОДСКАЗКА: для аудио взгляните на: /questions/10076764/zapuskat-prilozheniya-s-ispolzovaniem-audio-v-dok-kontejnere/10076766#10076766
С объемами данных докера очень легко выставить сокет домена 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, которые были разработаны для решения ваших проблем.
Вы также можете использовать подпользователя: https://github.com/timthelion/subuser
Это позволяет вам упаковать много приложений графического интерфейса в докер. Firefox и emacs были протестированы до сих пор. С Firefox WebGL не работает, хотя. Хром не работает вообще.
РЕДАКТИРОВАТЬ: Звук работает!
РЕДАКТИРОВАТЬ 2: С тех пор, как я впервые опубликовал это, subuser значительно прогрессировал. Теперь у меня есть веб-сайт http://subuser.org/ и новая модель безопасности для подключения к X11 через мост XPRA.
OSX
У Юргена Вайгерта лучший ответ, который у меня работал в Ubuntu, однако в OSX докер работает внутри VirtualBox, и поэтому решение не работает без дополнительной работы.
У меня это работает с этими дополнительными ингредиентами:
- Xquartz (OSX больше не поставляется с сервером X11)
- переадресация сокетов с помощью socat (brew install socat)
- 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 это немного проще:
- Установите MobaXterm для Windows
- Запустите MobaXterm
- Настройка X-сервера: Настройки -> X11 (вкладка) -> установить X11 Remote Access на полный
- Используйте этот 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
Совместное использование дисплея хоста: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
Вот облегченное решение, которое позволяет избежать необходимости устанавливать какие-либо 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
Хотя ответ Юргена Вайгерта, по сути, охватывает это решение, мне сначала было не ясно, что там описано. Поэтому я добавлю свою точку зрения на случай, если кому-то еще понадобятся разъяснения.
Прежде всего, соответствующей документацией является X-страница безопасности.
Многочисленные интернет-источники предлагают просто установить Unix-разъем X11 и ~/.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
работает или как xauth
или X-клиенты фильтруют записи из файла 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-сервер сравнивает его с локальной копией.
Решение, приведенное по адресу http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/, похоже, является простым способом запуска приложений с графическим интерфейсом изнутри контейнеров (я пробовал использовать 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/
Это не просто, но это хорошее решение, которое обеспечивает паритет функциональности докера с полной виртуализацией рабочего стола. Оба Xfce4 или IceWM для Ubuntu и CentOS работают, и noVNC
Опция облегчает доступ через браузер.
https://github.com/ConSol/docker-headless-vnc-container
Работает noVNC
так же как tigerVNC
vncserver. Тогда это вызывает startx
для данного оконного менеджера. К тому же, libnss_wrapper.so
используется для эмуляции управления паролями для пользователей.
Другие решения должны работать, но вот решение для 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
Lord.garbage предлагает другое решение для запуска приложений с графическим интерфейсом в контейнере без использования перенаправления VNC, SSH и X11. Здесь тоже упоминается.
Если вы хотите запустить приложение с графическим интерфейсом без головы, тогда читайте здесь. Что вам нужно сделать, это создать виртуальный монитор с xvfb
или другое подобное программное обеспечение. Это очень полезно, если вы хотите запускать тесты Selenium, например, в браузерах.
Что-то нигде не упоминалось, что некоторые программы на самом деле сами используют песочницу с контейнерами Linux Так, например, Chrome никогда не будет работать нормально, если вы не используете соответствующий флаг --privileged
при запуске контейнера.
Я опаздываю на вечеринку, но для пользователей Mac, которые не хотят идти по пути XQuartz, вот рабочий пример, который создает образ Fedora с использованием среды рабочего стола (xfce) с использованием Xvfb
а также VNC
, Все просто и работает:
- https://github.com/ddual/docker_recipes
- https://github.com/ddual/docker_recipes/tree/master/fedora_gui
На 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, если хотите / нуждаетесь.
Мне удалось запустить видеопоток с USB-камеры с помощью opencv
в docker
выполнив следующие действия:
Разрешить докеру доступ к X-серверу
xhost +local:docker
Создайте сокет X11 Unix и файл аутентификации X
XSOCK=/tmp/.X11-unix XAUTH=/tmp/.docker.xauth
Добавьте соответствующие разрешения
xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
Установите скорость рендеринга Qt на "native", чтобы он не обходил движок рендеринга X11.
export QT_GRAPHICSSYSTEM=native
Скажите Qt не использовать MIT-SHM (разделяемую память) - так это также должно быть безопаснее с точки зрения безопасности
export QT_X11_NO_MITSHM=1
Обновите команду запуска докера
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.
Исходя из ответа Юргена Вайгерта, у меня есть некоторые улучшения:
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 при каждом перезапуске системы и входе пользователя в систему.
Для рендеринга OpenGL с драйвером Nvidia используйте следующее изображение:
https://github.com/thewtex/docker-opengl-nvidia
Для других реализаций OpenGL убедитесь, что образ имеет ту же реализацию, что и хост.
Вы можете разрешить пользователю 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
Еще один ответ, если вы уже создали изображение:
вызвать docker без sudo ( Как исправить docker: проблема с запрещенным доступом)
использовать один и тот же пользователь USER & home & passwd для общего ресурса хоста и контейнера (советы: используйте имя пользователя вместо имени пользователя)
папка dev для зависимых от драйвера библиотек для правильной работы
плюс Х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).
Так что этот тип использования больше подходит для разработчика, я думаю.
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.
(Убунту 18.04, 20.04)
https://github.com/fcwu/docker-ubuntu-vnc-desktop обеспечивает удобную настройку. Эта установка не минимизирована. Хорошо бы минимизировать. Но у меня просто нет времени, и это работает каждый раз, когда я пытаюсь, поэтому я просто использую его. С другой стороны, поскольку он не минимизирован, он имеет тенденцию тестировать более сложные программы, которые вы действительно можете увидеть, чтобы увидеть, что они действительно работают с бесконечным количеством ловушек Docker. Кроме того, поскольку настройки прерываются при каждом обновлении гостя/хоста, минимизация, возможно, будет работать только в течение ограниченного периода времени, пока вам не придется снова минимизировать этот проект.
Чтобы запустить его, просто запустите:
sudo docker run --name ubvnc -p 6080:80 -p 5900:5900 dorowu/ubuntu-desktop-lxde-vnc:focal
Затем на хосте либо:
посетите: http://127.0.0.1:6080/#/ , который запускает noVNC более ограниченный клиент JavaScript VNC
бежать:
sudo apt-get install tigervnc-viewer xtigervncviewer :5900
Чтобы перейти в полноэкранный режим, нажмите F8 и щелкните пункт меню или просто F8, а затем T: https://superuser.com/questions/285843/how-do-i-switch-in-out-of-fullscreen-mode . -from-the-command-line-in-realvnc После этого вам может потребоваться закрыть и снова открыть экран, чтобы изображение стало больше.
Я также пробовал , но при прокрутке Firefox на YouTube это было намного медленнее.
Внутри
vinagre
, вы можете перейти в полноэкранный режим , чтобы увидеть весь рабочий стол
Чтобы бросить просто убить
docker
на терминале. И перезапустить машину:
sudo docker start ubvnc
а затем снова подключитесь к VNC. Затем, чтобы выйти из машины:
sudo docker stop ubvnc
Вам нужно подождать несколько секунд, пока сервер VNC на гостевой машине запустится, прежде чем вы сможете подключиться.
Хром внутри гостя не запускается из меню. Если вы попытаетесь запустить его из командной строки, это объясняет, почему:
Running as root without --no-sandbox is not supported. See https://crbug.com/638180.
поэтому просто запустите его из CLI с помощью:
chromium-browser --no-sandbox
Однако Firefox это не волнует.
TODO: без звука.
--device /dev/snd
не помогло:
- Как воспроизвести звук в контейнере Docker на Mac OS Yosemite
- https://forums.docker.com/t/how-to-get-sound/36527
- https://github.com/fcwu/docker-ubuntu-vnc-desktop/issues/49
РЕДАКТИРОВАТЬ: они добавили для него раздел: https://github.com/fcwu/docker-ubuntu-vnc-desktop/tree/e4922ce92f945fc482994b7a0fd95ca5de7295b3#sound-preview-version-and-linux-only
Смотрите также:
Протестировано на:
- Хост Ubuntu 19.04,
fcwu/docker-ubuntu-vnc-desktop
,dorowu/ubuntu-desktop-lxde-vnc
идентификатор изображения: 70516b87e92d. - Хост Ubuntu 21.10,
dorowu/ubuntu-desktop-lxde-vnc:focal
(Убунту 20.04)
Докер с сетью МОСТ. для 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
Здесь есть много хороших ответов о том, как подключить приложение с графическим интерфейсом в контейнере докера к X-серверу, работающему на хост-машине, или как запустить виртуальный X-сервер и подключиться к контейнеру, используя VNC для доступа к нему.
Однако есть другое решение (которое весьма полезно, скажем, для киосков или домашних кинотеатров) - вы можете запустить X-сервер внутри контейнера докеров с выводом видео на монитор, подключенный к вашему хост-компьютеру.
Сначала создадим том докера для хранения сокета X11:
docker volume create --name xsocket
Теперь мы можем создать образ с помощью X Server:
FROM ubuntu
RUN apt-get update && \
DEBIAN_FRONTEND='noninteractive' apt-get install -y xorg
CMD /usr/bin/X :0 -nolisten tcp vt1
Давайте создадим его, запустим и сохраним сокет X11 в томе докера:
docker build . -t docker-x-server:latest
docker run --privileged -v xsocket:/tmp/.X11-unix -d docker-x-server:latest
Теперь мы можем запустить приложение с графическим интерфейсом пользователя в другом контейнере докеров (ура!) И указать его на наш X-сервер, используя
xsocket
объем:
docker run --rm -it -e DISPLAY=:0 -v xsocket:/tmp/.X11-unix:ro stefanscherer/xeyes
Если вам нужен ввод (например, клавиатура), установите
xserver-xorg-input-evdev
упаковать и добавить
-v /run/udev/data:/run/udev/data
поскольку по умолчанию в контейнерах нет udev .
Вы даже можете избавиться от
--privileged
флаг путем предоставления
SYS_TTY_CONFIG
возможность и привязка некоторых устройств к контейнеру:
docker run --name docker-x-server --device=/dev/input --device=/dev/console --device=/dev/dri --device=/dev/fb0 --device=/dev/tty --device=/dev/tty1 --device=/dev/vga_arbiter --device=/dev/snd --device=/dev/psaux --cap-add=SYS_TTY_CONFIG -v xsocket:/tmp/.X11-unix -d docker-x-server:latest