Advertisement
Advertisement


Can you run GUI applications in a Docker container?


Question

How can you run GUI applications in a Docker container?

Are there any images that set up vncserver or something so that you can - for example - add an extra speedbump sandbox around say Firefox?

2018/07/24
1
417
7/24/2018 9:59:47 AM

Accepted Answer

You can simply install a vncserver along with Firefox :)

I pushed an image, vnc/firefox, here: docker pull creack/firefox-vnc

The image has been made with this 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'

This will create a Docker container running VNC with the password 1234:

For Docker version 18 or newer:

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

For Docker version 1.3 or newer:

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

For Docker before version 1.3:

docker run -p 5900 creack/firefox-vnc x11vnc -forever -usepw -create
2019/04/15
242
4/15/2019 10:26:02 PM

Xauthority becomes an issue with newer systems. I can either discard any protection with xhost + before running my docker containers, or I can pass in a well prepared Xauthority file. Typical Xauthority files are hostname specific. With docker, each container can have a different host name (set with docker run -h), but even setting the hostname of the container identical to the host system did not help in my case. xeyes (I like this example) simply would ignore the magic cookie and pass no credentials to the server. Hence we get an error message 'No protocol specified Cannot open display'

The Xauthority file can be written in a way so that the hostname does not matter. We need to set the Authentication Family to 'FamilyWild'. I am not sure, if xauth has a proper command line for this, so here is an example that combines xauth and sed to do that. We need to change the first 16 bits of the nlist output. The value of FamilyWild is 65535 or 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
2014/08/13

I just found this blog entry and want to share it here with you because I think it is the best way to do it and it is so easy.

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

PROS:
+ no x server stuff in the docker container
+ no vnc client/server needed
+ no ssh with x forwarding
+ much smaller docker containers

CONS:
- using x on the host (not meant for secure-sandboxing)

in case the link will fail someday I have put the most important part here:
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

build the image:

docker build -t firefox .

and the run command:

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

of course you can also do this in the run command with sh -c "echo script-here"

HINT: for audio take a look at: https://stackoverflow.com/a/28985715/2835523

2018/06/07

With docker data volumes it's very easy to expose xorg's unix domain socket inside the container.

For example, with a Dockerfile like this:

FROM debian
RUN apt-get update
RUN apt-get install -qqy x11-apps
ENV DISPLAY :0
CMD xeyes

You could do the following:

$ docker build -t xeyes - < Dockerfile
$ XSOCK=/tmp/.X11-unix/X0
$ docker run -v $XSOCK:$XSOCK xeyes

This of course is essentially the same as X-forwarding. It grants the container full access to the xserver on the host, so it's only recommended if you trust what's inside.

Note: If you are concerned about security, a better solution would be to confine the app with mandatory- or role-based-access control. Docker achieves pretty good isolation, but it was designed with a different purpose in mind. Use AppArmor, SELinux, or GrSecurity, which were designed to address your concern.

2014/09/11

You can also use subuser: https://github.com/timthelion/subuser

This allows you to package many gui apps in docker. Firefox and emacs have been tested so far. With firefox, webGL doesn't work though. Chromium doesn't work at all.

EDIT: Sound works!

EDIT2: In the time since I first posted this, subuser has progressed greatly. I now have a website up subuser.org, and a new security model for connecting to X11 via XPRA bridging.

2015/08/17

OSX

Jürgen Weigert has the best answer that worked for me on Ubuntu, however on OSX, docker runs inside of VirtualBox and so the solution doesn't work without some more work.

I've got it working with these additional ingredients:

  1. Xquartz (OSX no longer ships with X11 server)
  2. socket forwarding with socat (brew install socat)
  3. bash script to launch the container

I'd appreciate user comments to improve this answer for OSX, I'm not sure if socket forwarding for X is secure, but my intended use is for running the docker container locally only.

Also, the script is a bit fragile in that it's not easy to get the IP address of the machine since it's on our local wireless so it's always some random IP.

The BASH script I use to launch the container:

#!/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

I'm able to get xeyes and matplotlib working with this approach.

Windows 7+

It's a bit easier on Windows 7+ with MobaXterm:

  1. Install MobaXterm for windows
  2. Start MobaXterm
  3. Configure X server: Settings -> X11 (tab) -> set X11 Remote Access to full
  4. Use this BASH script to launch the container

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 running on PC

2017/05/23