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
With openjdk:8u111-jdk-alpine, installing dejavu fix the problem:
For example:
Dockerfile:
FROM openjdk:8u111-jdk-alpine
# Needed to fix 'Fontconfig warning: ignoring C.UTF-8: not a valid language tag'
ENV LANG en_GB.UTF-8
# JRE fails to load fonts if there are no standard fonts in the image; DejaVu is a good choice,
# see https://github.com/docker-library/openjdk/issues/73#issuecomment-207816707
RUN apk add --update ttf-dejavu && rm -rf /var/cache/apk/*
VOLUME /tmp
COPY /target/*.jar app.jar
ENTRYPOINT ["java","-Xmx100m","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"]