How Do I Run a Java App with a GUI in Docker?

Docker is best suited for running services vs. applications that have GUIs. However, it is possible to run applications that have X11 based GUIs on Docker using x11vnc. It is a rather complex topic.

Let's start with the basics, HelloWorldSwing.java

mkdir apps  
cat <<\EOF > apps/HelloWorldSwing.java  
import javax.swing.*;        

public class HelloWorldSwing {  
    private static void createAndShowGUI() {
        JFrame frame = new JFrame("HelloWorldSwing");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JLabel label = new JLabel("<html><div style='font-size: 100pt'>Hello World</div></html>");
        label.putClientProperty("JComponent.sizeVariant", "large");
        frame.getContentPane().add(label);
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }
}
EOF  

OK, we have a Java program. Now we need to compile it.

docker run -v$(pwd)/apps:/apps --name javac.app openjdk:7-jdk-alpine javac /apps/Hello/HelloWorldSwing.java  

Now for the fun part. Let's bring up a Docker container running x11vnc and Java 8. We'll use Java 8 from Azul Systems vs. OpenJDK.

First we need to create some files:

mkdir profile.d  
cat <<\EOF > profile.d/javac.sh  
#!/bin/sh

export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/X11R6/bin:/usr/bin/X11:/usr/openwin/bin:/usr/dt/bin:/opt/kde4/bin:/opt/kde3/bin:/opt/gnome/bin:/usr/bin:/bin:/usr/sfw/bin:/usr/local/bin:/usr/lib/jvm/zulu-8-amd64/jre/bin  
EOF  
cat <<\EOF > xsession  
#!/bin/bash
# ~/.Xclients, start my programs.

xterm -ls -geometry 190x70+80+30 &

echo Starting Window Manager...

exec lwm >> ~/.lwm-errors 2>&1

# eof
EOF  
cat <<\EOF > Dockerfile  
FROM debian:jessie-slim

RUN     apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0x219BD9C9  
RUN     echo "deb http://repos.azulsystems.com/debian stable  main" >> /etc/apt/sources.list.d/zulu.list  
RUN     apt-get -qq update  
RUN    apt-get install -y vim net-tools netcat  
RUN    apt-get install -y x11vnc xvfb  
RUN    apt-get install -y lwm  
RUN    apt-get -yq install zulu-8; true

RUN    mkdir /root/.vnc

COPY    xsession /root/.xsession  
RUN    chmod +x /root/.xsession

ADD    profile.d /etc/profile.d

EXPOSE  5900  
EOF  
cat <<\EOF > rungui  
#!/bin/bash
docker build -t debian:gui --build-arg REBUILD=${RANDOM} . 2>&1 | tee build.out

#docker rm -f gui.app
docker run -d -p 3000:3000 -p 3000:3000/udp -p 5900:5900 -v$(pwd)/apps:/root/apps --name gui.app debian:gui init  
docker exec -it gui.app su - -c 'x11vnc -forever -nopw -create'  
EOF  
chmod +x rungui  

Let's start the Docker container where the app lives:

./rungui

We'll need a VNC viewer. I like this one:

http://tigervnc.org/

For testing, we can just disable all the security and passwords in the VNC viewer. Then connect to the Docker container. Note: you must use the IP address of the host running the Docker engine. If this is a VM, the network interface must be bridged or port forwarding of 5900 must be used.

At this point you will have a shell running in an xterm. Just execute the program using the java command:

cd apps/Hello  
java HelloWorldSwing