使用Spring Boot应用程序减少Docker映像的大小

下午好


最近,我面临着使用docker映像在kubernetes集群中启动spring boot 2应用程序的任务。 这个问题并不新鲜,很快我就在Google中找到了示例并将其打包。 我为找不到jdk11的高山映像感到非常惊讶,并希望苗条足够小,但是当我将映像发送到docker注册表时,我注意到它的大小几乎为422兆字节。 在猫的下面描述了我如何通过Spring Boot和Java 11将docker镜像减少到144 MB。



应用程式


如前所述,我的应用程序是使用Spring Boot 2构建的,并且是关系数据库上的REST API包装器(使用@RepositoryRestResource)。 我的依赖项包括:


org.springframework.boot:spring-boot-starter-data-rest org.springframework.boot:spring-boot-starter-data-jpa org.flywaydb:flyway-core org.postgresql:postgresql 

收集的jar文件的大小为37.6 MB。


Dockerfile:


 FROM openjdk:11-jdk-slim WORKDIR /home/demo ARG REVISION COPY target/spring-boot-app-${REVISION}.jar app.jar ENTRYPOINT ["java","-jar","app.jar"] 

组装的结果是,根据docker images命令的输出,我得到了一个大小为422 mb的图像。 有趣的是,当使用过时的8-jdk-slim图像时,尺寸减小到306 mb。


尝试1:另一张基本图片


逻辑上的第一步是尝试找到更轻量的图像,最好是基于高山。 我扫描了最受欢迎的Java存储库:



(11个是当前的LTS版本,而8个是因为仍然有足够数量的应用程序无法迁移到较新的版本)


包含图像和标签的表格(〜2700),其大小在撰写本文时在此处


以下是其中一些:


 openjdk 8 488MB openjdk 8-slim 269MB openjdk 8-alpine 105MB openjdk 8-jdk-slim 269MB openjdk 8-jdk-alpine 105MB openjdk 8-jre 246MB openjdk 8-jre-slim 168MB openjdk 8-jre-alpine 84.9MB openjdk 11 604MB openjdk 11-slim 384MB openjdk 11-jdk 604MB openjdk 11-jdk-slim 384MB openjdk 11-jre 479MB openjdk 11-jre-slim 273MB adoptopenjdk/openjdk8 alpine 221MB adoptopenjdk/openjdk8 alpine-slim 89.7MB adoptopenjdk/openjdk8 jre 200MB adoptopenjdk/openjdk8 alpine-jre 121MB adoptopenjdk/openjdk11 alpine 337MB adoptopenjdk/openjdk11 alpine-slim 246MB adoptopenjdk/openjdk11 jre 218MB adoptopenjdk/openjdk11 alpine-jre 140MB 

因此,如果将基本映像更改为采用openjdk / openjdk11:alpine-jre,则可以使用该应用程序将映像减少到177 mb。


尝试2:自定义运行时


自从jdk9发行和模块化以来,就可以构建自己的运行时,该运行时仅包含应用程序所需的那些模块。 您可以在此处阅读有关此功能的更多信息。


让我们尝试确定测试Spring Boot应用程序所需的模块:


 ~/app ᐅ jdeps -s target/app-1.0.0.jar app-1.0.0.jar -> java.base app-1.0.0.jar -> java.logging app-1.0.0.jar -> not found 

好的,看来jdeps无法处理使用spring boot创建的fat-jar,但是我们可以解压缩存档并编写类路径:


 ~/app ᐅ jdeps -s -cp target/app-1.0.0/BOOT-INF/lib/*.jar target/app-1.0.0.jar.original Error: byte-buddy-1.9.12.jar is a multi-release jar file but --multi-release option is not set ~/app ᐅ jdeps -s --multi-release 11 -cp target/app-1.0.0/BOOT-INF/lib/*.jar target/app-1.0.0.jar.original Error: aspectjweaver-1.9.2.jar is not a multi-release jar file but --multi-release option is set 

在这种情况下,当前会打开一个错误: https : //bugs.openjdk.java.net/browse/JDK-8207162


我尝试下载jdk12以获得此信息,但遇到以下错误:


 Exception in thread "main" com.sun.tools.classfile.Dependencies$ClassFileError ... Caused by: com.sun.tools.classfile.ConstantPool$InvalidEntry: unexpected tag at #1: 53 

通过ClassNotFoundException的试验,错误和模块搜索,我确定我的应用程序需要以下模块:


  • java.base
  • java.logging
  • java.sql
  • java.naming
  • java.management
  • java.instrument
  • java.desktop
  • java.security.jgss

可以使用以下命令收集它们的跑步时间:


 jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.logging,java.sql,java.naming,java.management,java.instrument,java.desktop,java.security.jgss --output /usr/lib/jvm/spring-boot-runtime 

让我们尝试使用以下模块构建基本的docker映像:


 FROM openjdk:11-jdk-slim RUN jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,java.logging,java.sql,java.naming,java.management,java.instrument,java.desktop,java.security.jgss --output /usr/lib/jvm/spring-boot-runtime FROM debian:stretch-slim COPY --from=0 /usr/lib/jvm/spring-boot-runtime /usr/lib/jvm/spring-boot-runtime RUN ln -s /usr/lib/jvm/spring-boot-runtime/bin/java /usr/bin/java 

并收集:


 docker build . -t spring-boot-runtime:openjdk-11-slim 

结果,该大小为106兆字节,大大小于使用openjdk找到的大多数基本映像。 如果将其用于我的应用程序,则结果大小将为144兆字​​节。


此外,如果所有Spring Boot应用程序具有相似的依赖关系,我们可以将spring-boot-runtime:openjdk-11-slim用作基础映像。 在各种依赖关系的情况下,可以对每个应用程序使用多阶段映像程序集,其中在第一阶段将收集Java运行时,而在第二阶段将添加具有该应用程序的存档。


 FROM openjdk:11-jdk-slim RUN jlink --no-header-files --no-man-pages --compress=2 --strip-debug --add-modules java.base,YOUR_MODULES --output /usr/lib/jvm/spring-boot-runtime FROM debian:stretch-slim COPY --from=0 /usr/lib/jvm/spring-boot-runtime /usr/lib/jvm/spring-boot-runtime WORKDIR /home/demo ARG REVISION COPY target/app-${REVISION}.jar app.jar ENTRYPOINT ["/usr/lib/jvm/spring-boot-runtime/bin/java","-jar","app.jar"] 

结论


当前,大多数用于Java的docker映像都有足够大的容量,这可能会对应用程序的启动时间产生负面影响,尤其是在服务器上尚未存在必要的层时。 结合使用带有jre的标签或使用Java模块化,您可以构建自己的运行时,这将显着减小应用程序映像的大小。

Source: https://habr.com/ru/post/zh-CN457476/


All Articles