Can you run GUI applications in a Docker container?

前端 未结 22 2475
南旧
南旧 2020-11-22 06:12

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 e

相关标签:
22条回答
  • 2020-11-22 06:40

    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.

    0 讨论(0)
  • 2020-11-22 06:40

    You can allow the Docker user (here: root) to access the X11 display:

    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
    
    0 讨论(0)
  • 2020-11-22 06:47

    If you want to run a GUI application headless, then read here. What you have to do is to create a virtual monitor with xvfb or other similar software. This is very helpful if you want to run Selenium tests for example with browsers.

    Something not mentioned anywhere is that some software actually themselves use sand-boxing with Linux containers. So for example Chrome will never run normally if you don't use the appropriate flag --privileged when running the container.

    0 讨论(0)
  • 2020-11-22 06:47

    I managed to run a video stream from an USB camera using opencv in docker by following these steps:

    1. Let docker access the X server

      xhost +local:docker
      
    2. Create the X11 Unix socket and the X authentication file

      XSOCK=/tmp/.X11-unix
      XAUTH=/tmp/.docker.xauth
      
    3. Add proper permissions

      xauth nlist $DISPLAY | sed -e 's/^..../ffff/' | xauth -f $XAUTH nmerge -
      
    4. Set the Qt rendering speed to "native", so it doesn't bypass the X11 rendering engine

      export QT_GRAPHICSSYSTEM=native
      
    5. Tell Qt to not use MIT-SHM (shared memory) - that way it should be also safer security-wise

      export QT_X11_NO_MITSHM=1
      
    6. Update the docker run command

      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
      

    Note: When you finish the the project, return the access controls at their default value - xhost -local:docker

    More details: Using GUI's with Docker

    Credit: Real-time and video processing object detection using Tensorflow, OpenCV and Docker

    0 讨论(0)
  • 2020-11-22 06:48

    Here's a lightweight solution that avoids having to install any X server, vnc server or sshd daemon on the container. What it gains in simplicity it loses in security and isolation.

    It assumes that you connect to the host machine using ssh with X11 forwarding.

    In the sshd configuration of the host, add the line

    X11UseLocalhost no
    

    So that the forwarded X server port on the host is opened on all interfaces (not just lo) and in particular on the Docker virtual interface, docker0.

    The container, when run, needs access to the .Xauthority file so that it can connect to the server. In order to do that, we define a read-only volume pointing to the home directory on the host (maybe not a wise idea!) and also set the XAUTHORITY variable accordingly.

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

    That is not enough, we also have to pass the DISPLAY variable from the host, but substituting the hostname by the ip:

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

    We can define an alias:

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

    And test it like this:

    dockerX11run centos xeyes
    
    0 讨论(0)
  • 2020-11-22 06:48

    While the answer by Jürgen Weigert essentially covers this solution, it wasn't clear to me at first what was being described there. So I'll add my take on it, in case anyone else needs clarification.

    First off, the relevant documentation is the X security manpage.

    Numerous online sources suggest just mounting the X11 unix socket and the ~/.Xauthority file into the container. These solutions often work by luck, without really understanding why, e.g. the container user ends up with the same UID as the user, so there's no need for magic key authorization.

    First off, the Xauthority file has mode 0600, so the container user won't be able to read it unless it has the same UID.

    Even if you copy the file into the container, and change the ownership, there's still another problem. If you run xauth list on the host and container, with the same Xauthority file, you'll see different entries listed. This is because xauth filters the entries depending on where it's run.

    The X client in the container (i.e. GUI app) will behave the same as xauth. In other words, it doesn't see the magic cookie for the X session running on the user's desktop. Instead, it sees the entries for all the "remote" X sessions you've opened previously (explained below).

    So, what you need to do is add a new entry with the hostname of the container and the same hex key as the host cookie (i.e. the X session running on your desktop), e.g.:

    containerhostname/unix:0   MIT-MAGIC-COOKIE-1   <shared hex key>
    

    The catch is that the cookie has to be added with xauth add inside the container:

    touch ~/.Xauthority
    xauth add containerhostname/unix:0 . <shared hex key>
    

    Otherwise, xauth tags it in a way that it's only seen outside the container.

    The format for this command is:

    xauth add hostname/$DISPLAY protocol hexkey
    

    Where . represents the MIT-MAGIC-COOKIE-1 protocol.

    Note: There's no need to copy or bind-mount .Xauthority into the container. Just create a blank file, as shown, and add the cookie.

    Jürgen Weigert's answer gets around this by using the FamilyWild connection type to create a new authority file on the host and copy it into the container. Note that it first extracts the hex key for the current X session from ~/.Xauthority using xauth nlist.

    So the essential steps are:

    • Extract the hex key of the cookie for the user's current X session.
    • Create a new Xauthority file in the container, with the container hostname and the shared hex key (or create a cookie with the FamilyWild connection type).

    I admit that I don't understand very well how FamilyWild works, or how xauth or X clients filter entries from the Xauthority file depending where they're run. Additional information on this is welcome.

    If you want to distribute your Docker app, you'll need a start script for running the container that gets the hex key for the user's X session, and imports it into the container in one of the two ways explained previously.

    It also helps to understand the mechanics of the authorization process:

    • An X client (i.e. GUI application) running in the container looks in the Xauthority file for a cookie entry that matches the container's hostname and the value of $DISPLAY.
    • If a matching entry is found, the X client passes it with its authorization request to the X server, through the appropriate socket in the /tmp/.X11-unix directory mounted in the container.

    Note: The X11 Unix socket still needs to be mounted in the container, or the container will have no route to the X server. Most distributions disable TCP access to the X server by default for security reasons.

    For additional information, and to better grasp how the X client/server relationship works, it's also helpful to look at the example case of SSH X forwarding:

    • The SSH server running on a remote machine emulates its own X server.
    • It sets the value of $DISPLAY in the SSH session to point to its own X server.
    • It uses xauth to create a new cookie for the remote host, and adds it to the Xauthority files for both the local and remote users.
    • When GUI apps are started, they talk to SSH's emulated X server.
    • The SSH server forwards this data back to the SSH client on your local desktop.
    • The local SSH client sends the data to the X server session running on your desktop, as if the SSH client was actually an X client (i.e. GUI app).
    • The X server uses the received data to render the GUI on your desktop.
    • At the start of this exchange, the remote X client also sends an authorization request, using the cookie that was just created. The local X server compares it with its local copy.
    0 讨论(0)
提交回复
热议问题