【问题标题】:Docker and Java - FontConfiguration issueDocker 和 Java - FontConfiguration 问题
【发布时间】:2018-12-20 18:28:10
【问题描述】:

我们有一个 Java 应用程序,它使用第 3 方(Asposee,但我认为这不重要)生成 word 文档。该应用程序是从一个简单的 Docker 文件构建的:

FROM openjdk:10-jdk-slim
COPY target/*.jar /opt/
CMD $JAVA_HOME/bin/java $JAVA_OPTS -jar /opt/*.jar

当我们在本地构建应用程序(mvn package 然后docker build)并在k8s 中运行应用程序时,它运行良好。

但是,当我们使用 Jenkins 在 CI/CD 管道中构建映像时,在运行特定进程时会出现运行时异常,这显然需要额外的字体:

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)

在这种情况下,该项目在 Jenkins 中构建,由 docker 映像 maven:3.5.4-jdk-10-slim 编译。

我检查了两个 jar 文件(本地和来自 jenkins)并且类文件相同(如预期的那样)。

在这两种情况下,它都是相同的基本图像,所以我不明白可能有什么区别。在本地构建与在另一个 Docker 容器中构建时,Docker 中有什么不同吗?

编辑

我们查看了这两个 docker 镜像,发现了以下差异。

由于本地构建的图像ls -l /usr/lib 返回:

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

但在 Jenkins 内部构建的图像 ls -l /usr/lib 返回:

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

这真的很令人费解,因为我认为 Docker 总是会从相同的 Dockerfile 生成相同的图像

【问题讨论】:

    标签: java docker kubernetes aspose aspose.words


    【解决方案1】:

    使用 openjdk:8u111-jdk-alpine,安装 dejavu 解决问题:

    例如:

    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"]
    

    【讨论】:

    • 我用 openjdk:8u111-jdk-alpine 测试过。
    • 对我来说也适用于 openjdk:16-alpine
    • 使用openjdk:8-jdk-alpine 为我工作并且没有ENV LANG en_GB.UTF-8 声明
    【解决方案2】:

    安装libfontconfig1为我解决了这个问题(source):

    RUN apt-get install -y libfontconfig1 && rm -rf /var/lib/apt/lists/*
    

    【讨论】:

      【解决方案3】:

      我想我们找到了问题。

      在 Jenkins 上运行时,我们使用 docker:dind(Docker 内的 Docker)Docker 映像在构建中提供 docker 命令。此图像基于Alpine linux。运行 docker info 时,我们得到以下信息:

      在 Mac 上:

      Kernel Version: 4.9.87-linuxkit-aufs
      Operating System: Docker for Mac
      

      关于詹金斯:

      Kernel Version: 4.4.115-k8s
      Operating System: Alpine Linux v3.7 (containerized)
      

      Alpine linux 一定缺少那些字体。我们通过在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
      

      不确定这是最低要求的库,但它们成功了:D

      【讨论】:

      • 感谢您提供详细解释的答案 :-) 即使这不是我的问题版本的解决方案。
      【解决方案4】:

      只需在 Dockerfile 中添加以下内容

      RUN apk add --no-cache fontconfig ttf-dejavu
      

      【讨论】:

        【解决方案5】:

        如果您使用 Docker Desktop 在本地运行它并使用 docker 文件创建映像。 请将 Dockerfile 从 FROM openjdk:8-jdk-alpine 更改为 FROM 采用openjdk/openjdk11:ubi

        【讨论】:

          【解决方案6】:

          如果您尝试在 Java/Spring boot 中进行操作,则在 Dockerfile 中添加以下内容在 java 11 中对我有用。

          # Font packages to be added for java 11
          RUN apk update \
           && apk add fontconfig \
           && apk add ttf-dejavu
          RUN ln -s /usr/lib/libfontconfig.so.1 /usr/lib/libfontconfig.so && \
              ln -s /lib/libuuid.so.1 /usr/lib/libuuid.so.1 && \
              ln -s /lib/libc.musl-x86_64.so.1 /usr/lib/libc.musl-x86_64.so.1
          ENV LD_LIBRARY_PATH /usr/lib
          

          【讨论】:

            猜你喜欢
            • 2019-09-06
            • 2020-04-24
            • 2019-09-01
            • 2015-06-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-06-16
            相关资源
            最近更新 更多