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


409

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

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


이 질문은 Windows가 아닌 Linux (연령 및 답변 내용에 따라)에만 해당되는 것 같습니다. 그렇다면 제목을 수정하여이를 명확히 할 수 있습니까? 감사합니다
UuDdLrLrSs


몇 가지 아이디어는 HPC 시각화 컨테이너 사용 설명서 를 확인하십시오 .
kenorb

답변:


238

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

2
VNC 클라이언트를 사용하여 원격으로 보려면 어떻게해야합니까? IP + 포트를 입력해도 작동하지 않는 것 같습니다.
user94154

17
먼저, 할당 된 포트를 확인해야합니다 ( docker inspect <container id>또는 간단히 함으로써 docker ps방금 찾은 포트로 호스트의 IP에 연결합니다)
creack

9
creackfirefox-vnc 이미지 오류 : VNC 암호 입력 : stty : 표준 입력 : 장치 fget에 부적절한 ioctl : 해당 파일 또는 디렉토리가 없음 stty : 표준 입력 : 장치 x11vnc에 대한 부적절한 ioctl -usepw : 사용할 암호를 찾을 수 없습니다.
alfonsodev

6
사용 고정 표시기 잘> GUI를 실행하면 부두 노동자와 애플 리케이션 fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker
데니스 C에게

7
사용자 이름이 없으며 비밀번호가 답변에 명확하게 표시되며 모든 vnc 클라이언트가 수행합니다. 내 경우에는 기본 OSX를 좋아합니다. (파인더에서 command + K를 누르고 vnc : // <docker ip> : <container exposed port>에 연결하십시오)
creack

195

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

8
참고 -v $XSOCK:$XSOCK -v $XAUTH:$XAUTH로 짧아 질 수 있습니다-v $XSOCK -v $XAUTH
Piotr Aleksander Chmielowski

2
나를 위해 작동하지 @PiotrAleksanderChmielowski, Docker 버전 1.12.0, 빌드 8eab29e
tbc0

14
@Dirk : 당신은 대체 할 수 있습니다 :0$DISPLAY. xauth nlist $DISPLAY | ...그리고 의미 docker run -ti -e DISPLAY=$DISPLAY ...합니다. 일반적으로 X DISPLAY는 :0이지만 항상 그런 것은 아닙니다 (특히 ssh -X를 통해 연결하는 경우는 아님).
johndodo

4
Ubuntu 16.04에서 xauth /tmp/.docker.xauth600권한 이있는 파일을 만듭니다 . 결과적으로 docker container 내부의 xauth가 파일을 읽을 수 없습니다. xauth list도커 컨테이너 내에서 실행 하여 확인할 수 있습니다 . 이 문제를 해결하기 위해 명령 chmod 755 $XAUTH뒤에 추가 xauth nlist :0 | ...했습니다.
Abai

2
@Abai 444 또는 644로 충분하다면 755를 사용하는 이유는 무엇입니까?
Daniel Alder

68

방금이 블로그 항목을 찾아서 여기에 공유하고 싶습니다. 그것이 가장 좋은 방법이라고 생각하고 너무 쉽기 때문입니다.

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


Windows 7에서 어떻게 할 수 있습니까? X 서버를 설치해야합니까?
walksignison

3
여기서 대부분의 답변으로 이것은 Windows가 X 서버 창 시스템을 지원할 때까지 유닉스에만 적용됩니다.
A. Binzxxxxxx

Windows에 X 서버를 설치했거나 Docker 컨테이너에 X 서버를 번들로 제공 한 경우에도 효과가 있다고 생각하십니까?
walksignison

1
폴더 apt-get -y install sudo를 만들려면 Dockerfile 에 설치해야한다고 생각 /etc/sudoers.d합니다.
mulg0r

1
$ xhost +
Bandoos

52

도커 데이터 볼륨을 사용하면 컨테이너 내부에 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를 사용하십시오 .


5
또한 xhost와 같은 도구를 사용하여 다른 호스트에서 X 서버에 대한 액세스를 허용해야합니다. 완전히 열려면 xhost +호스트에서 사용 하십시오.
Tully

3
@Tully 만 xhost +local필요합니다. ~/.Xauthority그러나 컨테이너에서 파일을 사용 가능 하게하여 자체 인증 할 수 있도록하는 것이 좋습니다.
Aryeh Leib Taurog

3
(boot2docker를 사용하여) Mac에서 작동하게 했습니까?
Karl Forner

4
이것은 docker 1.5 이전의 Ubuntu 14.04 랩톱에서 나에게 다소 잘 작동했습니다. 하지만 우분투 15.04, docker 1.6.2에서 오류가 발생했습니다 Can't open display: :0. 어떤 아이디어?
cboettig 2016 년

6
내가 사용하는 xhost +si:localuser:$USER컨테이너를 시작하는 단지 사용자에게 권한을 부여 할 수 있습니다.
Nick Breen

26

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

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

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

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


3
하위 사용자는 여전히 매우 새롭고 상대적으로 테스트되지 않았습니다. 문제가 발생하면 버그 보고서를 제출하십시오!
timthelion

당신이 할 수있는 방법이 있다면 X11을 피할 것입니다. 킬러 응용 프로그램은 docker에서 tor proxy를 실행하고 하위 docker에서 플러그인이있는 전체 브라우저를 실행하여 방화벽 등으로 인해 모든 네트워크가 tor docker를 통해 강제 종료됩니다. 이것은 풍부한 콘텐츠를 통해 웹을 사용할 수 있기 때문에 웹 사용 편의성을 위해 현재 브라우저 브라우저 번들에 랩을 실행합니다.
Will

1
X11 보안에 문제가 있습니까? 아니면 이것이 창으로 작업하기를 원합니까? 아니면 이것이 원격으로 작동하기를 원합니까? 무엇보다도? 나는 vnc 로이 작업을 수행하는 것이 가능하다고 생각합니다 (vnc에 대한 종속성을 추가하기 때문에 기본 방법으로 만들지는 않지만). 하위 사용자 작업을 원격으로 수행하는 것은 실제로 불가능하거나 의미가 없습니다. :이이 또한 github.com/rogaha/docker-desktop는 하지만, 버그 리포트에서이 xpra 실제 생활에서 사용할 수 있습니다 보인다.
timthelion

24

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


bash 스크립트의 의미를 이해하지 못했습니다 .Windows에서 어떻게 실행합니까?
deller 17

@deller GIT를 사용하여 Windows에서 소프트웨어 개발을 수행하므로 GIT-bash 쉘을 사용할 수 있습니다.
Nick

나는 단계를 따랐다. 그러나, 나는 도착 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에 대한 공유 메모리 누락으로 인해 응용 프로그램에서 렌더링 결함과 불량 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 가속, 웹캠 및 프린터 공유 등과 같은 기능도 지원합니다.


18

다음 은 컨테이너에 X서버, vnc서버 또는 sshd데몬 을 설치하지 않아도되는 간단한 솔루션입니다 . 단순성으로 얻는 것은 보안과 격리에서 잃어 버립니다.

그것은 당신이 사용하여 호스트 시스템에 연결한다고 가정 ssh으로 X11전달.

에서 sshd호스트의 구성, 줄을 추가

X11UseLocalhost no

따라서 호스트의 전달 된 X 서버 포트가 모든 인터페이스 (뿐만 아니라 lo) 및 특히 Docker 가상 인터페이스에서 열리도록합니다 docker0.

컨테이너는 실행될 때 .Xauthority서버에 연결할 수 있도록 파일에 액세스해야 합니다. 이를 위해 호스트의 홈 디렉토리를 가리키는 읽기 전용 볼륨을 정의하고 (현명한 아이디어는 아닙니다!) XAUTHORITY변수를 적절하게 설정합니다 .

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

이것으로 충분하지 않으며 호스트에서 DISPLAY 변수를 전달해야하지만 ip로 호스트 이름을 대체해야합니다.

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

별명을 정의 할 수 있습니다.

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

다음과 같이 테스트하십시오.

dockerX11run centos xeyes

2
(이는 신뢰할 수있는 앱에 유용합니다. 그러나 모든 종류의 샌드 박싱에는 X 전달을 피하고 싶습니다.)
Will

1
전체 홈 디렉토리를 컨테이너에 마운트하지 않으려면 .Xauthority파일 자체를 마운트하면 됩니다 -v $HOME/.Xauthority:/root/.Xauthority -e XAUTHORITY=/root/.Xauthority.
Robert Haines

2
을 변경하는 대신 명령에 대한 X11UseLocalhost추가 옵션 --net=host을 사용할 수도 있습니다 docker run( here 참조 ).
ingomueller.net

--net=host컨테이너에서 포트를 열면 호스트에서도 열릴 것입니다.
MrR

16

Jürgen Weigert 의 답변 이 본질적으로이 솔루션을 다루고 있지만 처음에는 거기에 설명 된 내용이 명확하지 않았습니다. 다른 사람이 설명이 필요한 경우를 대비하여 테이크를 추가하겠습니다.

먼저 관련 문서는 X 보안 맨 페이지 입니다.

수많은 온라인 소스는 X11 유닉스 소켓과 ~/.Xauthority파일을 컨테이너에 마운트하는 것을 제안 합니다. 이러한 솔루션은 종종 컨테이너 사용자가 사용자와 동일한 UID로 끝나는 이유를 실제로 이해하지 못해 운이 좋게 작동하므로 매직 키 인증이 필요하지 않습니다.

먼저 Xauthority 파일의 모드는 0600이므로 컨테이너 사용자는 동일한 UID가 없으면 파일을 읽을 수 없습니다.

파일을 컨테이너에 복사하고 소유권을 변경하더라도 여전히 다른 문제가 있습니다. xauth list동일한 Xauthority파일 을 사용하여 호스트 및 컨테이너에서 실행 하면 다른 항목이 나열됩니다. xauth실행 위치에 따라 항목을 필터링 하기 때문 입니다.

컨테이너의 X 클라이언트 (예 : GUI 앱)는와 동일하게 작동합니다 xauth. 다시 말해, 사용자의 데스크탑에서 실행중인 X 세션의 매직 쿠키가 표시되지 않습니다. 대신, 이전에 연 모든 "원격"X 세션에 대한 항목이 표시됩니다 (아래에 설명 됨).

따라서 컨테이너의 호스트 이름과 호스트 쿠키와 동일한 16 진 키 (예 : 데스크탑에서 실행중인 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 컨테이너 에 복사하거나 바인드 마운트 할 필요가 없습니다 . 표시된대로 빈 파일을 만들고 쿠키를 추가하십시오.

Jürgen Weigert 의 답변은 FamilyWild연결 유형을 사용하여 호스트에서 새 권한 파일을 작성하고 컨테이너에 복사 하여이 문제를 해결합니다. 먼저을 ~/.Xauthority사용하여 현재 X 세션에 대한 16 진 키를 추출합니다 xauth nlist.

따라서 필수 단계는 다음과 같습니다.

  • 사용자의 현재 X 세션에 대한 쿠키의 16 진 키를 추출하십시오.
  • 컨테이너 호스트 이름과 공유 16 진 키를 사용하여 컨테이너에 새 Xauthority 파일을 작성하거나 FamilyWild연결 유형 으로 쿠키를 작성하십시오 .

FamilyWild작동 방식 xauth또는 X 클라이언트가 실행 위치에 따라 Xauthority 파일에서 항목을 필터링 하는 방법을 잘 이해하지 못한다는 것을 인정 합니다. 이에 대한 추가 정보는 환영합니다.

Docker 앱을 배포하려면 사용자의 X 세션에 대한 16 진 키를 가져 와서 앞에서 설명한 두 가지 방법 중 하나로 컨테이너로 가져 오는 컨테이너를 실행하기위한 시작 스크립트가 필요합니다.

또한 권한 부여 프로세스의 메커니즘을 이해하는 데 도움이됩니다.

  • 컨테이너에서 실행중인 X 클라이언트 (예 : GUI 응용 프로그램)는 Xauthority 파일에서 컨테이너의 호스트 이름 및 값과 일치하는 쿠키 항목을 찾습니다 $DISPLAY.
  • 일치하는 항목이 발견되면 X 클라이언트는 권한 부여 요청과 함께 /tmp/.X11-unix컨테이너에 마운트 된 디렉토리 의 해당 소켓을 통해 X 서버로 해당 항목을 전달합니다 .

참고 : X11 Unix 소켓은 여전히 ​​컨테이너에 마운트해야합니다. 그렇지 않으면 컨테이너에 X 서버에 대한 경로가 없습니다. 대부분의 배포는 보안상의 이유로 기본적으로 X 서버에 대한 TCP 액세스를 비활성화합니다.

추가 정보를 얻고 X 클라이언트 / 서버 관계의 작동 방식을보다 잘 이해하려면 SSH X 전달의 예를 살펴 보는 것도 도움이됩니다.

  • 원격 시스템에서 실행되는 SSH 서버는 자체 X 서버를 에뮬레이트합니다.
  • $DISPLAYSSH 세션 의 값이 자체 X 서버를 가리 키도록 설정합니다.
  • 그것은 사용하는 xauth원격 호스트에 대한 새로운 쿠키를 생성하고,에 추가 Xauthority로컬 및 원격 사용자를위한 파일입니다.
  • GUI 앱이 시작되면 SSH의 에뮬레이트 된 X 서버와 통신합니다.
  • SSH 서버는이 데이터를 로컬 데스크탑의 SSH 클라이언트로 다시 전달합니다.
  • 로컬 SSH 클라이언트는 마치 SSH 클라이언트가 실제로 X 클라이언트 (예 : GUI 앱) 인 것처럼 데스크탑에서 실행중인 X 서버 세션으로 데이터를 보냅니다.
  • X 서버는 수신 된 데이터를 사용하여 데스크탑에서 GUI를 렌더링합니다.
  • 이 교환이 시작되면 원격 X 클라이언트도 방금 작성된 쿠키를 사용하여 권한 부여 요청을 보냅니다. 로컬 X 서버는 로컬 X 서버와 로컬 X 서버를 비교합니다.

12

이것은 가볍지 않지만 전체 데스크톱 가상화와 도커 기능 패리티를 제공하는 훌륭한 솔루션입니다. Ubuntu 및 CentOS 용 Xfce4 또는 IceWM이 모두 작동하며이 noVNC옵션을 사용하면 브라우저를 통해 쉽게 액세스 할 수 있습니다.

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

의 vncserver noVNC와 함께 실행 됩니다 tigerVNC. 그런 다음 startx주어진 창 관리자를 호출 합니다. 또한 libnss_wrapper.so사용자의 비밀번호 관리를 에뮬레이트하는 데 사용됩니다.


누구든지 이것을 테스트 했습니까?
guilhermecgs

3
@guilhermecgs 네, 잘 작동합니다. 그 이후로 나는 xpra루트가없는 도커 에서도 시도 했습니다. 루트리스 X. xpra는 가장 적합한 IMO였으며 VNC보다 효율적입니다.
dashesy

명확하게하기 위해 ...이 이미지로 전체 데스크탑 환경 (GNOME, KDE)을 경험할 수 있습니까?
guilhermecgs 2016 년

나는 Xfce4와 IceWM (그 저장소에 있음) 만 시도했습니다. 물론 경험은 제한적입니다. 예를 들어 고정 장치에 전달 --device /dev/...하고 필요한 --cap권한을 설정 하지 않으면 장착 장치가 데스크탑 (gvfs)에 표시되지 않습니다 . 그것은 격리의 목적을 상실하지만 장치를 통과 할 수 있습니다. 약간의 조정으로 VNC에서 그놈 / KDE를 실행할 수 있다고 생각합니다. Nvidia 카드 (VNC 또는 Xpra 없음)가있는 도커에서 여러 개의 X를 실행 했으므로 확실히 가능합니다.
dashesy

우리는 지금까지 시도하지 않았습니다. 이것에 대한 가장 큰 도전은 작동하는 D- 버스 데몬을 불러오는 것입니다. 그놈 또는 KDE 데스크탑의 대부분이 필요합니다. 수있는 우분투 데스크탑 LXDE-VNC의 프로젝트는 당신이 도움이됩니다.
toschneck

11

http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/에 제공된 솔루션 은 컨테이너 내부에서 GUI 응용 프로그램을 시작하는 쉬운 방법 인 것 같습니다 (Firefox를 사용해 보았습니다) 우분투 14.04 이상)하지만 저자가 게시 한 솔루션에 약간의 추가 변경이 필요하다는 것을 알았습니다.

특히 컨테이너를 실행하기 위해 저자는 다음과 같이 언급했습니다.

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

그러나 (같은 사이트에 대한 특정 의견을 기반으로) 두 가지 추가 옵션이 있음을 발견했습니다.

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

    -net=host 

파이어 폭스가 제대로 작동하려면 컨테이너를 실행하는 동안 지정해야합니다.

    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도 커가 고정 디렉토리에서 볼륨 마운트를 자동으로 거부하므로 볼륨으로 사용하면 더 이상 작동하지 않습니다.
Christian Hujer

1
사용중인 배포판에 따라 다릅니다. CentOS에서 X11 Unix 소켓을 바인드 마운트 할 수 있습니다. 또한 무엇을 이해하는 것이 중요합니다 --network=host. 컨테이너가 호스트의 네트워크 스택에 대한 전체 액세스 권한을 부여하므로 수행하려는 작업에 따라 바람직하지 않을 수 있습니다. 데스크탑에서 컨테이너화 된 GUI를 실행하는 것만으로도 문제가되지 않습니다.
orodbhen


7

헤드리스 GUI 애플리케이션을 실행하려면 여기 를 읽으 십시오 . 당신이해야 할 일은 xvfb또는 다른 유사한 소프트웨어 로 가상 모니터를 만드는 것 입니다. 예를 들어 브라우저에서 Selenium 테스트를 실행하려는 경우 매우 유용합니다.

어디에도 언급되지 않은 것은 일부 소프트웨어 자체가 실제로 Linux 컨테이너와 샌드 박스를 사용한다는 것입니다. 예를 들어 --privileged컨테이너를 실행할 때 적절한 플래그를 사용하지 않으면 Chrome이 정상적으로 실행되지 않습니다 .


6

나는 파티에 늦게 해요,하지만 XQuartz의 길을 가고 싶지 않아 맥 사용자를 위해, 여기에 데스크탑 환경 (XFCE)를 사용하여, 페도라 이미지 구축 작업 예입니다 XvfbVNC. 간단하고 작동합니다.

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

Jürgen Weigert 의 답변을 바탕으로 몇 가지 개선 사항이 있습니다.

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 파일을 배치하고 $ XAUTH 파일 대신 $ XAUTH_DIR 디렉토리를 도커 컨테이너에 마운트하는 데 사용되는 $ XAUTH_DIR 디렉토리를 생성한다는 것입니다.

이 방법의 장점은 / tmp에 $ XAUTH_DIR이라는 빈 폴더를 만들고 모드를 777로 변경하는 /etc/rc.local에 명령을 작성할 수 있다는 것입니다.

tr '\n' '\000' < /etc/rc.local | sudo tee /etc/rc.local >/dev/null
sudo sed -i 's|\x00XAUTH_DIR=.*\x00\x00|\x00|' /etc/rc.local >/dev/null
tr '\000' '\n' < /etc/rc.local | sudo tee /etc/rc.local >/dev/null
sudo sed -i 's|^exit 0.*$|XAUTH_DIR=/tmp/.docker.xauth; rm -rf $XAUTH_DIR; install -m 777 -d $XAUTH_DIR\n\nexit 0|' /etc/rc.local

시스템 재시작시, 사용자 로그인 전에 컨테이너의 재시작 정책이 "항상"인 경우 docker는 $ XAUTH_DIR 디렉토리를 자동으로 마운트합니다. 사용자 로그인 후 ~ / .profile에 $ XAUTH 파일을 생성하는 명령을 작성할 수 있으며 컨테이너는이 $ XAUTH 파일을 자동으로 사용합니다.

tr '\n' '\000' < ~/.profile | sudo tee ~/.profile >/dev/null
sed -i 's|\x00XAUTH_DIR=.*-\x00|\x00|' ~/.profile
tr '\000' '\n' < ~/.profile | sudo tee ~/.profile >/dev/null
echo "XAUTH_DIR=/tmp/.docker.xauth; XAUTH=\$XAUTH_DIR/.xauth; touch \$XAUTH; xauth nlist \$DISPLAY | sed -e 's/^..../ffff/' | xauth -f \$XAUTH nmerge -" >> ~/.profile

결국 컨테이너는 시스템을 다시 시작하고 사용자가 로그인 할 때마다 Xauthority 파일을 자동으로 가져옵니다.


4

다른 솔루션은 작동하지만 여기에 대한 솔루션이 docker-compose있습니다.

이 오류를 해결하려면 $ DISPLAY 및 .X11-unix를 docker에 전달하고 docker를 시작한 사용자에게 xhost에 대한 액세스 권한을 부여해야합니다.

docker-compose.yml파일 내 :

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

터미널 또는 스크립트에서 :

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


3

Docker 사용자 (여기서는 root)가 X11 디스플레이에 액세스하도록 허용 할 수 있습니다.

XSOCK=/tmp/.X11-unix
xhost +SI:localuser:root 
docker run -t -i --rm -v $XSOCK:$XSOCK:ro -e DISPLAY=unix$(DISPLAY) image 
xhost -SI:localuser:root

2

OSX (10.13.6, 높은 시에라)

유사 @Nick 의 대답했지만, 그의 해결책은 나를 위해 작동하지 않았다.

먼저을 실행하여 socat을 brew install socat설치하고 XQuartz를 설치 하십시오 ( https://www.xquartz.org/ )

그런 다음 의견 섹션의 다음 단계 ( http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/ )를 따르십시오 .

1. in one mac terminal i started:

socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

2. and in another mac terminal I ran:

docker run -ti --rm \
-e DISPLAY=$(ipconfig getifaddr en0):0 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
firefox

데비안 도커 컨테이너에서도 CLion을 시작할 수있었습니다.


1

BRIDGE 네트워크가있는 Docker. 디스플레이 관리자 lightdm이있는 Ubuntu 16.04의 경우 :

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. sudo없이 docker를 호출하십시오 (docker 를 수정하는 방법 : 허가 거부 문제가 있음 )

  2. 호스트와 컨테이너 공유간에 동일한 사용자 및 홈 및 암호 공유 (팁 : 사용자 이름 대신 사용자 ID 사용)

  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

많은 것들이 동일하다면 도커를 사용하는 요점은 무엇입니까? 글쎄, 내가 생각할 수있는 한 가지 이유는 패키지 depency hell ( https://en.wikipedia.org/wiki/Dependency_hell ) 을 극복하는 것입니다 .

따라서 이러한 유형의 사용법은 내가 생각하는 개발자에게 더 적합합니다.


이것은 나를 위해 일할 유일한 것입니다. 내 목적을 위해 이것을 최소화 할 수있었습니다 : docker run --network = host --volume = echo ~: / home / $ {USER} --user = id -u ${USER}--env = "DISPLAY"--volume = "/ etc / passwd : / etc / passwd : ro "-it 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 명령 업데이트

    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와 함께 GUI 사용

크레딧 : Tensorflow, OpenCV 및 Docker를 사용하여 실시간 및 비디오 처리 객체 감지


"X11 Unix 소켓 및 X 인증 파일 작성"은 파일을 작성하지 않고 변수 만 정의합니까?
MrR
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.