Docker openjdk-alpine 无法使用字体控件(fontconfig)的坑
问题背景
因为最近公司的java微服务都到容器运行~某些服务使用了hutool
工具类提供Excel生成功能,今天测试在测试环境灰度测试时候,发现了空指针的错误:
java.lang.NullPointerException
at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
at sun.awt.FontConfiguration.readFontConfigFile(FontConfiguration.java:219)
at sun.awt.FontConfiguration.init(FontConfiguration.java:107)
at sun.awt.X11FontManager.createFontConfiguration(X11FontManager.java:774)
at sun.font.SunFontManager$2.run(SunFontManager.java:431)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.SunFontManager.<init>(SunFontManager.java:376)
at sun.awt.FcFontManager.<init>(FcFontManager.java:35)
at sun.awt.X11FontManager.<init>(X11FontManager.java:57)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.lang.Class.newInstance(Class.java:442)
at sun.font.FontManagerFactory$1.run(FontManagerFactory.java:83)
at java.security.AccessController.doPrivileged(Native Method)
at sun.font.FontManagerFactory.getInstance(FontManagerFactory.java:74)
at java.awt.Font.getFont2D(Font.java:491)
at java.awt.Font.access$000(Font.java:224)
at java.awt.Font$FontAccessImpl.getFont2D(Font.java:228)
at sun.font.FontUtilities.getFont2D(FontUtilities.java:180)
at sun.font.StandardGlyphVector.initFontData(StandardGlyphVector.java:1126)
at sun.font.StandardGlyphVector.init(StandardGlyphVector.java:1115)
at sun.font.StandardGlyphVector.<init>(StandardGlyphVector.java:167)
at java.awt.Font.createGlyphVector(Font.java:2545)
而正常的开发环境暂时还是在宿主机用oralce jdk跑服务,未出现此问题。
问题分析及解决
问题分析
因为Java服务现在都是用openjdk:8-jdk-alpine
为基础镜像进行构建的,再通过看具体错误和经过一些google
,可以确定两个问题:
1.openjdk
不包括sum.awt
的字体控件
2.alpine linux
的基础镜像也未安装有fontconfig
和ttf-dejavu
字体。
解决
- 将
openjdk:8-jdk-alpine
更换成oraclejdk
或者使用openjdk:8-jdk
。但考虑到商业授权的问题,因此不更换,仍使用openjdk
,但又因为alpine
基础镜像已经是最小了,所以折中继续使用openjdk:8-jdk-alpine
- 在
dockerfile
构建文件中,安装fontconfig 和 ttf-dejavu
字体
FROM openjdk:8-jdk-alpine
# 安装 fontconfig 和 ttf-dejavu字体
RUN apk add fontconfig && apk add --update ttf-dejavu && fc-cache --force
最终方案是在
openjdk:8-jdk-alpine
基础镜像中再封装私有的镜像原因是Jenkins流水线上每次打包构建镜像都要 apk
fontconfig和ttf-dejavu
,构建过程非常慢!!!!
最终镜像Dockerfile
FROM openjdk:8-jdk-alpine
ENV TIME_ZONE="Asia/Shanghai"
RUN apk add fontconfig && apk add --update ttf-dejavu && fc-cache --force
RUN ln -snf /usr/share/zoneinfo/$TIME_ZONE /etc/localtime && \
echo $TIME_ZONE > /etc/timezone && \
addgroup -g 2888 xinsec && \
adduser -u 2888 -G xinsec -h /home/xinsec -D xinsec