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
Controllers use Java 11 by default If you are running one of the Jenkins Docker controller images that does not include a JDK version in its label, the Java runtime will switch from Java 8 to Java 11 with the upgrade. For example: Jenkins 2.306 running as jenkins/jenkins:latest uses Java 8.
Take advantage of Docker to ease Java development. Learn how to update a running Java codebase (without restarting the container) and to debug into a remotely running containerized Java app.
Use a JRE, not a JDK When creating a Docker image, we should only assign the necessary resources to function correctly. This means that we should start by using an appropriate Java Runtime Environment (JRE) for your production image and not the complete Java Development Kit (JDK).
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"]
Installing libfontconfig1
solved the problem for me (source):
RUN apt-get install -y libfontconfig1 && rm -rf /var/lib/apt/lists/*
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With