Running a GUI from a Docker container
In order to run a GUI application from a Docker container and display its GUI on the host OS, several steps are needed;
Which display to use?
The container needs to be aware of the display to use. In order to make the display available, you can pass the DISPLAY environment variable to the container. docker-compose describes the environment/volume mappings/port mappings and other things of docker containers. This makes it easier to run containers in a quick and reproducible way and avoids long command lines.
docker-compose
You can do this by providing it in a docker-compose.yml file. See for example below. The environment indicates the host DISPLAY variable is passed as DISPLAY variable to the container.
Docker
In a Docker command (when not using docker-compose), you would do this with the -e flag or with --env. For example;
docker run --env DISPLAY=$DISPLAY containername
Allow access to the display
The Docker container needs to be allowed to present its screen on the Docker host. This can be done by executing the following command:
xhost local:root
After execution, during the session, root is allowed to use the current users display. Since the Docker daemon runs as root, Docker containers (in general!) now can use the current users display. If you want to persist this, you should add it to a start-up script.
Sharing the X socket
The last thing to do is sharing the X socket (don't ask me details but this is required...). This can be done by defining a volume mapping in your Docker command line or docker-compose.yml file. For Ubuntu this looks like you can see in the image below.
Spring Tool Suite from a Docker container
In order to give a complete working example, I'll show how to run Spring Tool Suite from a Docker container. In this example I'm using the Docker host JVM instead of installing a JVM inside the container. If you want to have the JVM also inside the container (instead of using the host JVM), look at the following and add that to the Dockerfile. As a base image I'm using an official Ubuntu image.
I've used the following Dockerfile:
FROM ubuntu:18.04
MAINTAINER Maarten Smeets <maarten.smeets@amis.nl>
ARG uid
LABEL nl.amis.smeetsm.ide.name="Spring Tool Suite" nl.amis.smeetsm.ide.version="3.9.5"
ADD https://download.springsource.com/release/STS/3.9.5.RELEASE/dist/e4.8/spring-tool-suite-3.9.5.RELEASE-e4.8.0-linux-gtk-x86_64.tar.gz /tmp/ide.tar.gz
RUN adduser --uid ${uid} --disabled-password --gecos '' develop
RUN mkdir -p /opt/ide && \
tar zxvf /tmp/ide.tar.gz --strip-components=1 -C /opt/ide && \
ln -s /usr/lib/jvm/java-10-oracle /opt/ide/sts-3.9.5.RELEASE/jre && \
chown -R develop:develop /opt/ide && \
mkdir /home/develop/ws && \
chown develop:develop /home/develop/ws && \
mkdir /home/develop/.m2 && \
chown develop:develop /home/develop/.m2 && \
rm /tmp/ide.tar.gz && \
apt-get update && \
apt-get install -y libxslt1.1 libswt-gtk-3-jni libswt-gtk-3-java && \
apt-get autoremove -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
rm -rf /tmp/*
USER develop:develop
WORKDIR /home/develop
ENTRYPOINT /opt/ide/sts-3.9.5.RELEASE/STS -data /home/develop/ws
I've used the following docker-compose.yml file:
version: '3'
services:
sts:
build:
context: .
dockerfile: Dockerfile
args:
uid: ${UID}
container_name: "sts"
volumes:
- /tmp/.X11-unix:/tmp/.X11-unix
- /home/develop/ws:/home/develop/ws
- /home/develop/.m2:/home/develop/.m2
- /usr/lib/jvm/java-10-oracle:/usr/lib/jvm/java-10-oracle
- /etc/java-10-oracle:/etc/java-10-oracle
environment:
- DISPLAY
user: develop
ports:
"8080:8080"
User id
Workspace folder and Maven repository
When working with Docker containers, it is a common practice to avoid storing state inside the container. State can be various things. I consider the STS application work-space folder and the Maven repository among them. This is why I've created the folders inside the container and mapped them in the docker-compose file to the host. They will use folders with the same name (/home/develop/.m2 and /home/develop/ws) on the host.
Java
My Docker container with only Spring Tool Suite was big enough already without having a more than 300Mb JVM inside of it (on Linux Java 10 is almost double the size of Java 8). I'm using the host JVM instead. I installed the host JVM on my Ubuntu development VM as described here.
In order to use the host JVM inside the Docker container, I needed to do 2 things:
Map 2 folders to the container:
And map the JVM path to the JRE folder onder STS: ln -s /usr/lib/jvm/java-10-oracle /opt/ide/sts-3.9.5.RELEASE/jre.
Seeing it work
Allow access to the display:
xhost local:root
Next make available the variable UID to the build:
export UID=$UID
Then build:
docker-compose build
Building sts
Step 1/10 : FROM ubuntu:18.04
---> 735f80812f90
Step 2/10 : MAINTAINER Maarten Smeets <maarten.smeets@amis.nl>
---> Using cache
---> 69177270763e
Step 3/10 : ARG uid
---> Using cache
---> 85c9899e5210
Step 4/10 : LABEL nl.amis.smeetsm.ide.name="Spring Tool Suite" nl.amis.smeetsm.ide.version="3.9.5"
---> Using cache
---> 82f56ab07a28
Step 5/10 : ADD https://download.springsource.com/release/STS/3.9.5.RELEASE/dist/e4.8/spring-tool-suite-3.9.5.RELEASE-e4.8.0-linux-gtk-x86_64.tar.gz /tmp/ide.tar.gz
---> Using cache
---> 61ab67d82b0e
Step 6/10 : RUN adduser --uid ${uid} --disabled-password --gecos '' develop
---> Using cache
---> 679f934d3ccd
Step 7/10 : RUN mkdir -p /opt/ide && tar zxvf /tmp/ide.tar.gz --strip-components=1 -C /opt/ide && ln -s /usr/lib/jvm/java-10-oracle /opt/ide/sts-3.9.5.RELEASE/jre && chown -R develop:develop /opt/ide && mkdir /home/develop/ws && chown develop:develop /home/develop/ws && rm /tmp/ide.tar.gz && apt-get update && apt-get install -y libxslt1.1 libswt-gtk-3-jni libswt-gtk-3-java && apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
---> Using cache
---> 5e486a4d6dd0
Step 8/10 : USER develop:develop
---> Using cache
---> c3c2b332d932
Step 9/10 : WORKDIR /home/develop
---> Using cache
---> d8e45440ce31
Step 10/10 : ENTRYPOINT /opt/ide/sts-3.9.5.RELEASE/STS -data /home/develop/ws
---> Using cache
---> 2d95751237d7
Successfully built 2d95751237d7
Successfully tagged t_sts:latest
docker-compose up
When you run a Spring Boot application on port 8080 inside the container, you can access it on the host on port 8080 with for example Firefox.
No comments:
Post a Comment