Although perhaps not a common occurrence, I would still like to be able to sometimes run GUI applications inside a Docker container. This may be required because an installer does not provide a silent option and has a GUI wizard I need to click my way through in order to set up the software that the container subsequently will run. It can also be because my development environment management is fully containerized, including management of IDEs and other graphical development tools. Whatever the motivation for running GUI in containers – it is my topic in this article. More specifically: running GUI applications in Docker containers that are managed Vagrant – a combination I have discussed in several earlier articles (First steps with provisioning of Docker containers using Vagrant as provider and Vagrant and Docker – Next and Advanced steps with folders, ports, volumes, linking and more).
Note: I am using Vagrant 1.7.4 and Oracle VirtualBox 4.3.18. (VirtualBox 5.0 apparently has interesting support for remote desktop and GUI on headless servers so that is one of my next explorations).
The steps in this case:
- Use Vagrant to provision a Docker container inside a Docker Host VM based on Ubuntu; this Docker container is set up with X-libraries
- Add a Desktop to the Docker Host VM: sudo apt-get install –no-install-recommends lubuntu-desktop
- Connect into the Docker container to use Puppet to provision a GUI application (in this case simply the Java JDK/JRE); commit the container and create a new image
- Halt Docker Host VM through Vagrant
- Start Docker Host VM through VirtualBox GUI – this will launch the GUI
- Login into Ubuntu Desktop, start a terminal session and launch a Docker container for the new Docker image using special options: -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix
- Run GUI application inside Docker Container
Note: at this point, Vagrant cannot access the Docker Host VM to control the Docker Container or provision new ones. Only when the Docker Host VM is stopped through the VirtualBox GUI can we once again work with the Docker Host VM and the containers inside through Vagrant. This is an unpleasant consequence – although primarily problematic when provisioning containers, not so much when running them. I hope to find a way to start Docker Host VM from Vagrant and somehow connect to the desktop through RDP or perhaps using new VirtualBox 5.0 features.
All sources – Vagrant, Docker and Puppet – can be found in GitHub: https://github.com/lucasjellema/vagrant-docker-puppet-desktop.
And Action
The starting point – as cloned from the Git repository – looks as follows:
Note that the files directory contains the Java installation files jdk-7u79-linux-x64.tar and UnlimitedJCEPolicyJDK7.zip.
Use Vagrant to provision a Docker container inside a Docker Host VM based on Ubuntu. Note that this Docker container is set up with X-libraries.
First, Vagrant will work on creating the Docker Host vm called dockerdesktophostvm.
Next, the Docker Container my-desktop-base-container is provisioned. This container is set up – as is specified in the Dockerfile – with Puppet and with the X-libraries required for GUI action (as the next figure shows).
After some (ample) time, the container is created:
Vagrant global-status shows both the container and the Docker host VM:
Our next step is to add a Desktop to the Docker Host VM, using vagrant ssh to connect into the VM and sudo apt-get install –no-install-recommends lubuntu-desktop to actually add the desktop.
This will take considerable time. Finally:
and the desktop is set up.
Still inside the Docker Host VM, we connect into the Docker container with docker exec -it <container id> bash (after using docker ps -a to get hold of the container id for my-desktop-base-container)
Now we use Puppet to provision a GUI application (in this case simply the Java JDK/JRE) – puppet apply –debug –modulepath=/puppet/modules /puppet/manifests/base.pp.
When Puppet is done – Java is set up and ready to run.
Exit the container, commit the container and create a new image – docker commit <containerId > me/java-gui:1.0:
Exit from the Docker Host VM, halt the container (vagrant halt) and the Docker Host VM (vagrant halt <dockerhost vm identifier) through Vagrant
Start Docker Host VM through VirtualBox GUI – this will launch the GUI
Login – vagrant/vagrant:
And open a terminal:
You can check whether Docker is available and what the situation is for containers:
Launch a Docker container for the new Docker image using special options: -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix – and run the GUI application inside Docker Container:
First: docker run -ti -v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY me/java-gui:1.0 /bin/bash
Then inside the container: su – oracle, navigate to the bin folder for the Java JRE and run jcontrol. When the GUI appears – we have achieved our objective.
Edit: with VirtualBox 5.0 the workflow can indeed be different. This release of Oracle VirtualBox supports the ability to enter the GUI for a box that was started by Vagrant from the command line.
So adding the desktop to the Docker Host VM, exit the VM, halt the VM with Vagrant, then restart the VM with Vagrant. From VirtualBox GUI you can see the VM running and using the new right mouse option Show on the VM, we can open a remote desktop session and working inside the VM.
Resources
Source at in GitHub: https://github.com/lucasjellema/vagrant-docker-puppet-desktop.
Running GUI apps with Docker by Fábio Rehm
Getting to know Docker – a better way to do virtualization? by Mark Nelson
If you don’t mind the unix socket -> tcp overhead, you could save yourself from installing the desktop, tinkering with virtual box and being boxed into a VM with: http://sourceforge.net/projects/xming/