We’ve got a Java application that generates word documents using a 3rd party (Asposee but I don’t think it matters here). The app is built from a simple Docker file:
FROM openjdk:10-jdk-slim COPY target/*.jar /opt/ CMD $JAVA_HOME/bin/java $JAVA_OPTS -jar /opt/*.jar
When we build the application locally (mvn package
then docker build
) and run the application inside k8s
it works well.
However, when we build the image in our CI/CD pipeline with Jenkins we get a runtime exception when running through a specific process which apparently requires additional fonts:
Caused by: java.lang.NullPointerException: null at java.desktop/sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1288) at java.desktop/sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:225) at java.desktop/sun.awt.FontConfiguration.init(FontConfiguration.java:107) at java.desktop/sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:765) at java.desktop/sun.font.SunFontManager$2.run(SunFontManager.java:440) at java.base/java.security.AccessController.doPrivileged(Native Method) at java.desktop/sun.font.SunFontManager.<init>(SunFontManager.java:385) at java.desktop/sun.awt.FcFontManager.<init>(FcFontManager.java:35) at java.desktop/sun.awt.X11FontManager.<init>(X11FontManager.java:56)
In that case the project is buit in Jenkins, compiled by the docker image maven:3.5.4-jdk-10-slim
.
I’ve checked both jar files (locally and from jenkins) and the class files are the same (as expected).
In both cases it’s the same base image so I don’t understand what could be the difference. Is something different in Docker when building locally vs inside another Docker container?
EDIT
We’ve looked into both docker images and found the following difference.
Since locally built image ls -l /usr/lib
returns:
drwxr-xr-x 2 root root 4096 May 3 2017 X11 drwxr-xr-x 5 root root 4096 Apr 26 00:00 apt drwxr-xr-x 2 root root 4096 May 26 08:31 binfmt.d drwxr-xr-x 2 root root 4096 Jun 6 01:50 cgmanager drwxr-xr-x 2 root root 4096 Jun 6 01:50 dbus-1.0 drwxr-xr-x 2 root root 4096 Jun 6 01:51 dconf drwxr-xr-x 3 root root 4096 Jun 6 01:51 debug drwxr-xr-x 3 root root 4096 Apr 20 10:08 dpkg drwxr-xr-x 2 root root 4096 Jun 6 01:50 environment.d drwxr-xr-x 3 root root 4096 Apr 25 04:56 gcc drwxr-xr-x 2 root root 4096 Jun 6 01:51 glib-networking drwxr-xr-x 2 root root 4096 Apr 26 00:00 init drwxr-xr-x 1 root root 4096 Jun 6 01:51 jvm drwxr-xr-x 3 root root 4096 Jun 6 01:50 kernel lrwxrwxrwx 1 root root 20 Mar 4 09:49 libnih-dbus.so.1 -> libnih-dbus.so.1.0.0 -rw-r--r-- 1 root root 34824 Mar 4 09:49 libnih-dbus.so.1.0.0 lrwxrwxrwx 1 root root 15 Mar 4 09:49 libnih.so.1 -> libnih.so.1.0.0 -rw-r--r-- 1 root root 92184 Mar 4 09:49 libnih.so.1.0.0 drwxr-xr-x 3 root root 4096 Mar 29 19:47 locale drwxr-xr-x 3 root root 4096 Jun 6 01:50 lsb drwxr-xr-x 1 root root 4096 Jul 21 2017 mime drwxr-xr-x 2 root root 4096 Jun 6 01:50 modprobe.d drwxr-xr-x 2 root root 4096 May 26 08:31 modules-load.d -rw-r--r-- 1 root root 198 Jan 13 23:36 os-release drwxr-xr-x 3 root root 4096 Jun 6 01:51 ssl drwxr-xr-x 1 root root 4096 Jun 6 01:50 systemd drwxr-xr-x 2 root root 4096 Jun 6 01:50 sysusers.d drwxr-xr-x 2 root root 4096 Jul 21 2017 tar drwxr-xr-x 15 root root 4096 Feb 11 20:06 terminfo drwxr-xr-x 1 root root 4096 Jun 6 01:50 tmpfiles.d drwxr-xr-x 1 root root 4096 Apr 26 00:00 udev drwxr-xr-x 1 root root 16384 Jun 6 01:51 x86_64-linux-gnu
But inside Jenkins built image ls -l /usr/lib
returns:
drwxr-xr-x 5 root root 4096 Jun 25 00:00 apt drwxr-xr-x 3 root root 4096 Jul 3 01:00 debug drwxr-xr-x 3 root root 4096 Apr 20 10:08 dpkg drwxr-xr-x 3 root root 4096 Jun 17 03:36 gcc drwxr-xr-x 2 root root 4096 Jun 25 00:00 init drwxr-xr-x 1 root root 4096 Jul 3 01:00 jvm drwxr-xr-x 1 root root 4096 Jul 12 11:00 locale drwxr-xr-x 3 root root 4096 Jul 3 01:00 lsb drwxr-xr-x 1 root root 4096 May 16 07:47 mime -rw-r--r-- 1 root root 198 Jan 13 23:36 os-release drwxr-xr-x 3 root root 4096 Jul 3 01:00 ssl drwxr-xr-x 3 root root 4096 Apr 20 10:08 systemd drwxr-xr-x 2 root root 4096 May 16 07:47 tar drwxr-xr-x 15 root root 4096 May 21 08:54 terminfo drwxr-xr-x 2 root root 4096 Jun 25 00:00 tmpfiles.d drwxr-xr-x 3 root root 4096 Jun 25 00:00 udev drwxr-xr-x 2 root root 4096 May 3 2017 X11 drwxr-xr-x 1 root root 4096 Jul 3 01:00 x86_64-linux-gnu
This is really puzzling as I thought Docker would always produce the same image from identical Dockerfiles
Advertisement
Answer
I think we found the problem.
When running on Jenkins we use the docker:dind
(Docker inside docker) Docker image to provide the docker
command in the build. This image is based on Alpine
linux. When running docker info
we get the following:
On Mac:
Kernel Version: 4.9.87-linuxkit-aufs Operating System: Docker for Mac
On Jenkins:
Kernel Version: 4.4.115-k8s Operating System: Alpine Linux v3.7 (containerized)
Alpine
linux must be missing those fonts. We fixed the problem by manually installing them in the Dockerfile
:
RUN apt-get update && apt-get install --assume-yes apt-utils && apt-get install --assume-yes software-properties-common && apt-get install --assume-yes dbus && apt-get install --assume-yes cgmanager && apt-get install --assume-yes glib-networking && apt-get install --assume-yes libnih-dbus-dev && apt-get install --assume-yes dconf-cli && apt-get install --assume-yes fontconfig
Not sure this is the minimum required libraries but those did the trick 😀