Puget Systems print logo


Read this article at https://www.pugetsystems.com/guides/915
Dr Donald Kinghorn (Scientific Computing Advisor )

Docker and NVIDIA-docker on your workstation: Using Graphical Applications

Written on March 21, 2017 by Dr Donald Kinghorn

This is my fourth post about "Docker and NVIDIA-Docker on your Workstation". In this post I will go through how to attach your X server display to a Docker container so that you can run application that have GUIs or other graphical display output.

It is assumed that you have already installed the host OS, Docker-Engine, and NVIDIA-Docker as described in the "installation post". I also highly recommend that you have setup Docker to use Kernel User-Namespaces.

Here is a list of the first three posts in this series for reference,

I recommend that you do not use X-Window with your Docker containers unless you have configured Docker with User-Namespaces as I have outlined in previous posts. If you do this then you are using X-Window with Docker as your normal log-in user account rather than as root.

How to Run a GUI application from a Docker Container

The most common use of Docker is for servers and other "command-line" applications. What if you want to run an application that needs your desktop display? You can do this. The relevant Docker command flags are,

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

The flag -v /tmp/.X11-unix:/tmp/.X11-unix gives the container access to your X socket and -e DISPLAY=$DISPLAY sets the DISPLAY environment variable in the container the same as that of your desktop.

Note: You can add sound capability to a container with --device /dev/snd

Security: I believe that using X-Window with Docker in this way is as secure as if you were running any X-Window application with your normal user account. The reason for this is, if you are running Docker configured with User-Namespaces the way I have outlined then you are running with your normal user account from the perspective of the host!

Example: Compile and run CUDA nbody with OpenGL display output

This example is the kind of thing that I really wanted to be able to do easily with a Docker container. I'll start with the default NVIDIA CUDA 8 image and add the "freeglut3-dev" package to pull the needed dependencies into the container. Then compile nbody in the container and run it with openGL display output.

I have created a directory docker/cuda8 in my home directory and added put the CUDA "samples" source there. I will use this directory in the container.

  1. Start the container

nvidia-docker run -it -v $HOME/docker:/projects -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY nvidia/cuda
  1. cd to the nbody source directory and try to run make

cd projects/cuda8/samples/5_Simulations/nbody
>>> WARNING - libGL.so not found, ...
  1. No GL lib and a lot of other missing libs so lets install "freeglut3-dev" which will pull the dependencies we need.

apt-get update
apt-get install freeglut3-dev

Note: That will add a lot of packages to the image! They will add as a new "layer". We will save this modified container to a new image later.

  1. Try make again

make clean
  1. Now run nbody


You should be greeted with something like this;
nbody OpenGL GUI

That is screenshot of the running nbody application using the GPU for CUDA acceleration and using your X display to show the openGL output. ... From a Docker container!

How to Save a Modified Container to a new Image

We just made a significant modification to the container we started from the default NVIDIA cuda8-dev image. This will persist as long as we don't remove the container. You can exit from the container and then re-start it and all of your changes will still be there. However, adding the openGL support to the container is a useful thing so saving that as a new image so you (and others) could create new containers from it is a reasonable thing to do.

There are a couple of ways to save your modified container as a new image. I'll show you how to use commit. In a later post I'll go through how to create a Dockerfile and use that to build a new image with the same changes that we apply in the container.

Using docker commit

If you are still connected to the modified container go ahead and exit, then run docker ps -a which will output something like,

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS                      PORTS               NAMES
9fc3da506758        nvidia/cuda         "/bin/bash"         19 hours ago        Exited (0) 18 seconds ago                       awesome_payne

Make note of the container ID. In this case it is 9fc3da506758. To save this as a new image do,

docker commit 9fc3da506758 cuda8-dev-opengl

That will output a sha256 ID for the new image and save it to your image directory with the new name. Do docker images and you should see your saved image. For example,

docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
cuda8-dev-opengl    latest              3022f6beb3ef        18 seconds ago      1.75 GB
alpine              latest              4a415e366388        2 weeks ago         3.99 MB
nvidia/cuda         latest              1cce8839a2c5        2 weeks ago         1.62 GB

Note You can add tags then you commit an image. I could have used something like docker commit 9fc3da506758 cuda8-dev:opengl. Tags are usually used for versioning but you can use naming schemes to suit your taste.

Note You only need to use enough characters from the ID hash to uniquely identify the container or image. For example using 9fc for the example container above would be sufficient.

You can now remove the old modified container with docker rm 9fc You can verify that the container was remove with docker ps -a

To start a new container with the new image we committed do

nvidia-docker run -it -v $HOME/docker:/projects -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY cuda8-dev-opengl

That is just scratching the surface of what you can do! It is possible to run many GUI applications including application that use GPU compute acceleration.

I think it is good to keep something in mind when you start playing around with running GUI applications with Docker -- Just because you can do something doesn't mean that you should do it! You could get carried away trying to run all of your normal desktop application in containers, but why would you want to do that? The idea here is to have a good "Single-User-Docker-Workstation" that you can use wisely to manage application environments that could be problematic or complex to setup otherwise.

Happy computing --dbk

Tags: Docker, NVIDIA-docker, GPU

I usually need to do : xhost + , before it will work.

Posted on 2017-07-29 22:03:39

I am finding this impossible to do from a remote host. Have you tried to access what you created on a remote host? I understand there are some limitations/problems with X11.
The output using your example is this error:

CUDA error at bodysystemcuda_impl.h:183 code=30(cudaErrorUnknown) "cudaGraphicsGLRegisterBuffer(&m_pGRes[i], m_pbo[i], cudaGraphicsMapFlagsNone)"

I have looked and looked and nothing. Have you ever faced a similar problem?

Posted on 2018-12-08 01:17:07
Donald Kinghorn

Hi Pines, That's interesting and it's an obvious thing to want to do! ... but I haven't tried it. ... Oh wait , I have too sort of. It's not so much an X problem as it is a openGL problem. It can be a real pain to get GL working remotely. You have to have it setup on your local X server. I don't remember how to do it but that will get you on the right track. GL has to execute on your machine ... First thing to do is get something like glxgears working

Posted on 2018-12-10 17:00:39

Hey Donald,

Thanks for the awesome article.
I'm actually facing an error running the second make command (after I installed freeglut3-dev) which seems like:

make: /usr/local/cuda-10.0/bin/nvcc: Command not found
Makefile:304: recipe for target 'bodysystemcuda.o' failed
make: *** [bodysystemcuda.o] Error 127

Although when I run "nvcc" in the container shell it founds the executable.

I'm using Ubuntu18.

Thanks in advance,

Posted on 2019-06-11 13:16:27
Donald Kinghorn

Hi Alex, first this post is pretty old :-) however, really, this stuff should still work. I was thinking about this a couple of days ago, I haven't done this X binding for ages!

... let me check something ... OK, found the problem. The latest nvidia/cuda container image is at cuda 10.1 The Makefile that you have in the samples is configured for 10.0 You could get a newer copy of the cuda samples and try that ... I edited the nbody Makefile in the 10.0 samples that I had and changed
CUDA_PATH ?= /usr/local/cuda-10.0 to just /usr/local/cuda The code built with the 10.1 nvcc. It ran fine with nbody --benchmark but when I tried it with the GL display if dumped a bunch of openGL errors.

I think the first thing to try ti to get a copy of the cuda samples for 10.1 and try that

... let me try something else ... I tried using the tag :10.0-devel that also built the code OK but failed to run with GL errors.

I'm on Ubuntu 19.04 with the latest nvidia driver, I may be seeing a versioning problem or just one of those annoying openGL problems.

This should get you on the right track but if you hit the GL errors that I did it may be a pain to fix

Posted on 2019-06-12 21:41:56