[x11] Docker 컨테이너에서 GUI 응용 프로그램을 실행할 수 있습니까?

Docker 컨테이너 에서 GUI 응용 프로그램을 어떻게 실행할 수 있습니까?

vncserver예를 들어 Firefox와 같은 추가적인 스피드 범프 샌드 박스를 추가 할 수 있도록 설정 한 이미지가 있습니까?



답변

Firefox와 함께 간단히 vncserver를 설치할 수 있습니다 🙂

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'

암호로 VNC를 실행하는 Docker 컨테이너가 생성됩니다 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

버전 1.3 이전의 Docker의 경우 :

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


답변

Xauthority는 최신 시스템에서 문제가됩니다. 도커 컨테이너를 실행하기 전에 xhost +로 보호를 취소하거나 잘 준비된 Xauthority 파일을 전달할 수 있습니다. 일반적인 Xauthority 파일은 호스트 이름에 따라 다릅니다. docker를 사용하면 각 컨테이너마다 다른 호스트 이름 (docker run -h로 설정)을 가질 수 있지만 컨테이너의 호스트 이름을 호스트 시스템과 동일하게 설정해도 도움이되지 않습니다. xeyes (이 예제가 마음에 듭니다)는 단순히 매직 쿠키를 무시하고 자격 증명을 서버에 전달하지 않습니다. 따라서 ‘프로토콜을 지정하지 않았습니다. 디스플레이를 열 수 없습니다’라는 오류 메시지가 나타납니다.

호스트 이름이 중요하지 않도록 Xauthority 파일을 작성할 수 있습니다. 인증 패밀리를 ‘FamilyWild’로 설정해야합니다. xauth에 적절한 명령 줄이 있는지 확실하지 않으므로 xauth와 sed를 결합하는 예제가 있습니다. nlist 출력의 첫 16 비트를 변경해야합니다. 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/

장점 :
+ 도커 컨테이너에 x 서버 항목 없음
+ vnc 클라이언트 / 서버 필요
없음
+ x 전달을 사용하는 ssh 없음 + 훨씬 작은 도커 컨테이너

단점 :
-호스트에서 x 사용 (보안 샌드 박싱 용이 아님)

언젠가 링크가 실패하는 경우 가장 중요한 부분을 여기에

넣었습니다.

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을 참조하십시오.


답변

도커 데이터 볼륨을 사용하면 컨테이너 내부에 xorg의 유닉스 도메인 소켓을 노출하는 것이 매우 쉽습니다.

예를 들어 다음과 같은 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에 대한 전체 액세스 권한을 부여하므로 내부 내용을 신뢰하는 경우에만 권장됩니다.

참고 : 보안이 염려되는 경우 더 나은 솔루션은 앱을 필수 또는 역할 기반 액세스 제어 로 제한하는 것 입니다. Docker는 매우 우수한 격리를 달성하지만 다른 목적을 염두에두고 설계되었습니다. 우려 사항을 해결하도록 설계된 AppArmor , SELinux 또는 GrSecurity를 사용하십시오 .


답변

https://github.com/timthelion/subuser 하위 사용자를 사용할 수도 있습니다.

이를 통해 많은 GUI 응용 프로그램을 docker에 패키지 할 수 있습니다. Firefox와 emacs는 지금까지 테스트되었습니다. 파이어 폭스에서는 webGL이 작동하지 않습니다. Chromium이 전혀 작동하지 않습니다.

편집 : 소리가 작동합니다!

EDIT2 : 내가 이것을 처음 게시 한 이후로 하위 사용자가 크게 발전했습니다. 이제 웹 사이트 subuser.orgXPRA 브리징을 통해 X11에 연결하기위한 새로운 보안 모델이 있습니다 .


답변

OSX

Jürgen Weigert 는 우분투에서 나에게 가장 적합한 대답을했지만 OSX에서는도 커가 VirtualBox 내부에서 실행되므로 더 이상 작업하지 않으면 솔루션이 작동하지 않습니다.

다음과 같은 추가 재료로 작업하고 있습니다.

  1. Xquartz (OSX는 더 이상 X11 서버와 함께 제공되지 않음)
  2. socat을 사용한 소켓 포워딩 (brew install 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을 사용할 수 있습니다.

윈도우 7 이상

MobaXterm을 사용하는 Windows 7 이상에서는 조금 더 쉽습니다.

  1. Windows 용 MobaXterm 설치
  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

PC에서 실행되는 xeye


답변

다른 답변에서 언급했듯이 공유 호스트 표시 : 0에는 두 가지 단점이 있습니다.

  • 일부 X 보안 누출로 인해 컨테이너 격리가 중단됩니다. 예를 들어 xev또는 xinput로 키 로깅 이 가능하고로로 호스트 응용 프로그램을 원격 제어 할 수 있습니다 xdotool.
  • X 확장 MIT-SHM에 대한 공유 메모리 누락으로 인해 응용 프로그램에서 렌더링 결함과 불량 RAM 액세스 오류가 발생할 수 있습니다. (절연 저하 옵션으로 수정 가능 --ipc=host).

Xephyr에서이 문제를 해결하는 도커 이미지를 실행하는 예제 스크립트 아래

  • docker 응용 프로그램이 중첩 된 X 서버에서 실행될 때 X 보안 누출을 피합니다.
  • RAM 액세스 실패를 피하기 위해 MIT-SHM이 비활성화됩니다.
  • 로 컨테이너 보안이 향상되었습니다 --cap-drop ALL --security-opt no-new-privileges. 또한 컨테이너 사용자는 루트 가 아닙니다 .
  • Xephyr 디스플레이에 대한 액세스를 제한하기 위해 X 쿠키가 생성됩니다.

이 스크립트는 먼저 Xephyr에서 호스트 창 관리자를 실행하고, 두 번째는 도커 이미지, 선택적으로 세 번째로 이미지 명령을 실행할 인수를 예상합니다. docker에서 데스크탑 환경을 실행하려면 호스트 창 관리자 대신 “:”을 사용하십시오.

Xephyr 창을 닫으면 docker container 응용 프로그램이 종료됩니다. 도커 응용 프로그램을 종료하면 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 는 GPU 가속, 웹캠 및 프린터 공유 등과 같은 기능도 지원합니다.