使用alpine linux和jlink创建一个小型的docker镜像(85MB),因为OpenJDK11的docker镜像太大了(1GB)

首先

OpenJDK 11的Docker镜像可以在Docker Hub的官方存储库中找到。

唯一需要的:
只是…在使用这个时有点担心的是,

    • イメージサイズがそもそも大きい。約1GBもあります。

 

    jlinkを使っても、300MB以上ある

有一个问题,我想要将它变得更小一些。于是我试着看看能缩小多少!

前提 tí)

    • Java Flight Recorderが動くこと

 

    Spring Boot アプリケーションが動くこと

结果

我个人非常满意,成功将1GB压缩至85MB,不到原始大小的十分之一。

用 Docker images 命令查看大小的结果如下所示。

imageの種類jlink使用sizeopenjdk:11-jdkしない1GBopenjdk:11-jdkする468MB独自alpinelinuxしない336MB独自alpinelinuxする84.6MB

jdk11是EA版。我认为很快会能够制作出OpenJDK 11的官方镜像的小型版本。
Hiroki Matsumoto的独特Alpine Linux版本是:
https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/

請問有什麼問題?

详细描述OpenJDK 11官方镜像的问题。

图片尺寸很大。

$ sudo docker images |grep jdk
docker.io/openjdk                            11-jdk   f684efd78557  2 weeks ago         979 MB
$

由于JRE的FlightRecorder无法正常运行,所以我想使用JDK,但它有点太大了。
参考:Qiita – 使用OpenJDK11-JRE-SLIM无法实现FlightRecorder。

在官方版的OpenJDK 11中,即使使用jlink,它也不会变得更小。

以下的问题也在下面的链接中讨论:
https://github.com/docker-library/openjdk/issues/217

试着做一下…奇怪的是,结果变成了约400MB,图像大小也变成了约450MB左右。

$ docker run -it --rm openjdk:11-jdk /bin/sh
# ls -l /usr/lib/jvm/java-11-openjdk-amd64/lib/server/
total 34944
-rw-r--r-- 1 root root     1322 Jul 27 03:41 Xusage.txt
-r--r--r-- 1 root root 18210816 Jul 27 22:22 classes.jsa
-rw-r--r-- 1 root root    14440 Jul 27 03:41 libjsig.so
-rw-r--r-- 1 root root 17551048 Jul 27 03:41 libjvm.so  #まだ小さい
圧縮してみる
# jlink \
     --module-path /opt/java/jmods \
     --compress=2 \
     --add-modules java.base,java.logging,jdk.jfr  \
     --no-header-files \
     --no-man-pages \
     --output /opt/jdk-11-mini-runtime
#  ls -l /opt/jdk-11-mini-runtime/lib/server/
total 414452
-rw-r--r-- 1 root root      1322 Aug 14 09:41 Xusage.txt
-rw-r--r-- 1 root root     25384 Aug 14 09:41 libjsig.so
-rw-r--r-- 1 root root 424362808 Aug 14 09:41 libjvm.so #なんでや・・・
#

我要把图像尺寸变小!

让我们尝试使用Alpine Linux,并使用jlink来减小体积。

创建基于Alpine Linux的用于构建的映像。

我在想其他人是否也能从中受益,所以我公开分享。

以下是用中文对上述内容的本地化释义(只提供一种选项):

图像来源:https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/
Docker文件:https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/~/dockerfile/

非常抱歉我没有进行校验和…。

使用jlink创建一个小型的可执行图像。

使用多阶段构建方法进行构建。

    1. 在以上所创建的alpine linux + openjdk 11的镜像为基础上,使用jlink创建一个小型的java runtime模块。

 

    然后将runtime模块和jar模块复制到alpine linux的镜像中,创建一个新的镜像。
FROM hirokimatsumoto/alpine-openjdk-11:latest as jlink-package
# First: generate java runtime module by jlink.

RUN jlink \
     --module-path /opt/java/jmods \
     --compress=2 \
     --add-modules jdk.jfr,jdk.management.agent,java.base,java.logging,java.xml,jdk.unsupported,java.sql,java.naming,java.desktop,java.management,java.security.jgss,java.instrument \
     --no-header-files \
     --no-man-pages \
     --output /opt/jdk-11-mini-runtime

# Second: generate run image.
FROM alpine:3.8

ENV JAVA_HOME=/opt/jdk-11-mini-runtime
ENV PATH="$PATH:$JAVA_HOME/bin"

COPY --from=jlink-package /opt/jdk-11-mini-runtime /opt/jdk-11-mini-runtime
COPY target/k8s-jmc-sample-0.1.0-SNAPSHOT.jar /opt/spring-boot/

EXPOSE 30001 7199
CMD java \
    -XX:StartFlightRecording=name=sample,filename=/spring-boot/jfr/sample.jfr,delay=30s,maxage=2h,maxsize=10m,dumponexit=true,settings=/spring-boot/config/profile.jfc \
    -Dcom.sun.management.jmxremote.port=7199 \
    -Dcom.sun.management.jmxremote.rmi.port=7199 \
    -Dcom.sun.management.jmxremote.authenticate=false \
    -Dcom.sun.management.jmxremote.ssl=false \
    -jar /opt/spring-boot/k8s-jmc-sample-0.1.0-SNAPSHOT.jar \
    --server.port=${SPRING_SERVER_PORT} \
    --spring.config.location=/spring-boot/config/application.yaml

执行应用程序是https://github.com/h-r-k-matsumoto/k8s-jmc-sample。

迷上了迷上了

使用jdeps查看Spring Boot应用程序的依赖关系并不准确。

最开始我使用了jdeps,并确认了所需的模块,如下所示。

> jdeps --list-deps .\target\k8s-jmc-sample-0.1.0-SNAPSHOT.jar
   java.base
   java.logging
>

只要创建了这个运行时……在运行时,将会出现下面的错误。

Caused by: java.lang.ClassNotFoundException: java.sql.SQLException
        at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:471)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:588)
        at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:93)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)

唔,可能不能很好地追踪Spring Boot内部自动配置的部分吧…
因为有点麻烦,我随意地在这里添加了一些内容,可以参考一下:https://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html

请参考

    • OpenJDK official image: https://hub.docker.com/_/openjdk/

独自のalpine linux image: https://hub.docker.com/r/hirokimatsumoto/alpine-openjdk-11/

Spring Boot + jlinkの参考情報: https://dev.solita.fi/2018/01/24/Java9-modules-Spring-Boot-2-Docker.html