Альтернативы ssh X11-forwarding для контейнеров Docker

Я использую контейнер Docker в основном как изолированную среду разработки для R язык. (Использование R здесь ортогонально к остальной части поста, то есть вы можете просто принять любую общую программу, которая может работать в repl-сессия.) Много раз это будет включать в себя такие вещи, как прорисовка, создание графики и т. д.; и мне нужно посмотреть на это. Следовательно, я предпочел бы иметь возможность показа графики, которую я создал в своем контейнере. Вот как я это делаю до сих пор. Сначала я создаю Dockerfile, Оставляя тривиальные шаги, наиболее важными являются:

# Set root passwd 
RUN echo "root:test" | chpasswd

# Add user so that container does not run as root 
RUN useradd -m docker 
RUN echo "docker:test" | chpasswd 
RUN usermod -s /bin/bash docker 
RUN usermod -aG sudo docker 
ENV HOME /home/docker

RUN mkdir /var/run/sshd 
RUN mkdir -p /var/log/supervisor

# copy servisord.conf which lists the processes to be spawned once this 
# container is started (currently only one: sshd) 
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf

EXPOSE 22 
CMD ["/usr/bin/supervisord"]

Я создаю изображение, а затем запускаю контейнер с помощью:

docker run -d -p 127.0.0.1:5000:22 -h ubuntu-r -v /home/chb/files/Data:/home/docker/Data -P --name="rdev" ubuntu-r

и может затем SSH в мой контейнер:

ssh -X docker@localhost -p 5000.

Это даст мне то, что я хочу. Но я хотел бы знать, есть ли другой более дружественный к ресурсам способ получения графики / графического интерфейса пользователя из контейнера? (Я бы предпочел, если возможно, решения не будут включать vnc.)

3 ответа

Решение

Есть хороший и полу-простой способ получения графического вывода из контейнера Docker без необходимости запуска sshd демон внутри контейнера. Docker может обеспечить чистую производительность при запуске одного процесса, который в этом случае должен быть R, Запуск демона sshd, как бы мало это ни было, привнесет дополнительные издержки. Это не улучшится, если запустить демон sshd как дочерний процесс демона supervisor. С обоими можно обойтись, если хорошо использовать крепления. После создания образа, из которого предполагается запустить контейнер, мы запускаем интерактивный контейнер и связываем монтируем/tmp/.X11-unix папка в него. Я изложу всю команду и подробно объясню, что она делает:

docker run -i -t --rm \

  • -i устанавливает интерактивный сеанс; -t выделяет псевдотет; --rm делает этот контейнер эфемерным

-e DISPLAY=$DISPLAY \

  • устанавливает отображение хоста на дисплей локальных машин (который обычно :0)

-у докер \

  • -u указать процесс должен быть запущен пользователем (здесь docker) а не по руту. Этот шаг важен (vi)!

-v /tmp/.X11-unix:/tmp/.X11-unix:ro \

  • -v привязка монтирует X11 гнездо, проживающее в /tmp/.X11-unix на вашей локальной машине в /tmp/.X11-unix в контейнере и :ro делает сокет только для чтения.

--name = "rdev" ubuntu-r R

  • --name="" укажите название контейнера (здесь rdev); изображение, из которого вы хотите запустить контейнер (здесь ubuntu-r); процесс, который вы хотите запустить в контейнере (здесь R). (Последний шаг определения процесса необходим, только если вы не установили значение по умолчанию CMD или же ENTRYPOINT для вашего имиджа.)

После выдачи этой команды вы должны смотреть на красивые Rначать вывод. Если бы вы попробовали demo(graphics) чтобы увидеть, работает ли графический вывод, вы должны заметить, что это не так. Это из-за Xsecurity расширение, не позволяющее вам получить доступ к сокету. Теперь вы можете напечатать xhost + на вашем локальном компьютере и попробуйте demo(graphics) снова в вашем контейнере. Теперь у вас должен быть графический вывод. Однако этот метод настоятельно не рекомендуется, поскольку вы разрешаете доступ к вашему xsocket любому удаленному хосту, к которому вы в данный момент подключены. Пока вы взаимодействуете только с однопользовательскими системами, это может быть как-то оправдано, но как только в нем участвуют несколько пользователей, это будет абсолютно небезопасно! Следовательно, вы должны использовать менее опасный метод. Хороший способ - использовать интерпретированный сервер

xhost +si:localuser:username

который может быть использован для указания одного локального пользователя (см. man xhost). Это означаетusername должно быть имя пользователя, который запускает X11 сервер на вашей локальной машине и который запускает Docker-контейнер. Это также причина, по которой важно указывать пользователя при запуске вашего контейнера. Наконец, что не менее важно, всегда есть более сложное решение использования xauth а также .Xauthority файлы для предоставления доступа к X11 гнездо (см. man xauth). Это, однако, также будет включать в себя немного больше знаний о том, как X работает.

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

(1) с supervisor а также sshd работает в контейнере:

UID                 PID                 PPID                C                STIME               TTY                 TIME                CMD
root                4564                718                 1                18:16               ?                   00:00:00            /usr/bin/python /usr/bin/supervisord
root                4576                4564                0                18:16               ?                   00:00:00            /usr/sbin/sshd

при входе через ssh и работает R:

UID                 PID                 PPID                C                 STIME               TTY                 TIME                CMD
root                4564                718                 0                 18:16               ?                   00:00:00            /usr/bin/python /usr/bin/supervisord
root                4576                4564                0                 18:16               ?                   00:00:00            /usr/sbin/sshd
root                4674                4576                0                 18:17               ?                   00:00:00            sshd: docker [priv]   
chb                 4725                4674                0                 18:18               ?                   00:00:00            sshd: docker@pts/0
chb                 4728                4725                1                 18:18               pts/0               00:00:00            -bash

(2) с методом крепления:

UID                 PID                 PPID                C                 STIME               TTY                 TIME                CMD
chb                 4356                718                 0                 18:12               pts/4               00:00:00            /usr/local/lib/R/bin/exec/R --no-save --no-restore

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

/questions/16455501/mozhete-li-vyi-zapuskat-prilozheniya-s-graficheskim-interfejsom-v-docker-kontejnere/16455517#16455517 (все кредиты принадлежат Юргену Вайгерту)

Преимущества:

  • Внутри докера умереть UID не актуален (но я все же рекомендую не использовать root)
  • На хосте вам не нужно менять настройки безопасности (xhost +)

Основываясь на ответе lord.garbage, мы можем перенаправить сокет X11 хоста. Точно так же мы можем создать пользователя во время создания образа докера в соответствии с очень хорошей идеей Юргена Вайгерта, изложенной выше (спасибо Хьюго / Даниэлю). Однако что, если мы не хотим изменять xhost ACL или создавать образ, который статически привязан к учетные данные одного пользователя? Мы можем сделать еще одно уточнение:

При запуске вашего контейнера перенаправить идентификатор пользователя / группу из оболочки хоста:

      XSOCK=/tmp/.X11-unix
docker run -it --rm \
    -e HOST_USER=$(id -u) \
    -e HOST_GROUP=$(id -g) \
    -e HOST_USER_NAME=$(whoami) \
    -e DISPLAY=$DISPLAY \
    -v $XSOCK:$XSOCK \
    my_container:latest

Создайте сценарий оболочки и установите его как ENTRYPOINT вашего контейнера. В сценарии создайте нового пользователя с идентификатором пользователя / идентификатором группы хоста, а затем используйте sudo для запуска целевого приложения «как хост»:

      groupadd -o -g $HOST_GROUP docker
useradd -d /home/$HOST_USER_NAME -s /bin/bash -u $HOST_USER -g docker $HOST_USER_NAME
sudo -u $HOST_USER_NAME bash -c "<some bash commands etc.>"

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

Другие вопросы по тегам