使用JLINK为您的春季靴子Java应用程序创建较小的Docker图像
#java #docker #containersecurity

容器为软件开发和部署带来了新的灵活性和敏捷性。但是,他们还引入了恶意演员可以利用的新攻击表面。受损的容器可以使攻击者访问其他容器甚至主机系统。较小的伪像的较小图像已经在实现较小的攻击面方面有很大的帮助。

在这篇博客文章中,我们将介绍使用JLink优化Docker图像尺寸,增强应用程序安全性和性能的深入探索。我们将展示如何使用JLINK并将其与Docker集成以有效部署您的Spring Boot或General Java应用程序。

Jlink简介

Java是全球企业应用程序开发最常用的编程语言之一。但是,在Docker容器中部署Java应用程序时,开发人员通常会在Docker图像的大小上挣扎。解决此问题的方法之一是使用JLink,这是JDK 9中引入的工具。

jlink(Java Linker)是一种命令行工具,它将一组模块及其依赖项组装并优化到自定义运行时映像中。从本质上讲,这意味着它创建了最小的Java运行时环境,仅使用您的应用程序所需的模块。

$ jlink --module-path $JAVA_HOME/jmods:mlib --add-modules my.module --output myRunTime

在上述命令中,my.module是您的模块,myRuntime是Jlink将创建的自定义运行时映像。

Jlink在创建较小的Docker图像中的作用

为Java应用程序创建Docker映像时,图像的大小通常是一个问题 - 特别是对于春季启动应用程序,这些应用程序带有许多依赖关系。大型Docker映像可以导致更长的启动时间,增加存储成本和较慢的部署流程。

在Java的旧版本中,Java开发套件(JDK)带有Java运行时环境(JRE)。只需要JRE才能运行创建的Java文物。因此,在过去,通常在Docker映像中使用JRE或为您的容器选择JRE基本图像。 JAVA的较新版本并不总是随附JRE,尽管有些供应商可能仍会创建JRE和相应的基础图像。您可以使用这些或更具体的Java运行时为您的应用程序量身定制。

JLink使您只使用必要的模块创建最小的Java运行时。通过这样做,它大大降低了Docker图像的大小。例如,标准的Java运行时环境可能超过200 MB,但是使用JLINK,您可以将其降低到50 MB。

使用jlink进行弹簧靴Java应用程序

Spring Boot为您的应用程序创建一个胖罐,其中包含所有依赖项。此外,许多春季启动应用程序缺乏模块声明。这不一定是一个问题,但是我们需要确定应用程序需求及其所有依赖项的模块。

使用JDEP查找模块

JDEPS是一种Java工具,可显示软件包级或类级依赖关系。 Java 8中引入的工具可用于了解应用程序的依赖项,然后可以使用JLink来创建自定义运行时图。

确保我们所有的依赖项都位于一个目录中时,我们可以使用JDEP来打印依赖关系的摘要。

jdeps -cp 'mydeps/lib/*' -recursive --multi-release 17 -s target/MyJar.jar

同样,我们可以使用JDEP递归地打印所有用于Spring Boot应用程序和依赖项的模块依赖项。

jdeps --ignore-missing-deps -q  --recursive  --multi-release 17  --print-module-deps  --class-path 'mydeps/lib/*'  target/MyJar.jar

JDEPS生成的输出使JLINK可以创建Java运行时,该运行时仅包含此Spring-Boot应用程序所需的模块。

输出弹簧启动依赖项到文件夹中

如前所述,Spring Boot创建了一个胖罐,其中包含所有依赖性。但是,依赖项以特定方式包装在罐子内部,因此,JDEP不容易访问。有两个简单的解决方案可以使用JDEP获得依赖项。

  • 解开Spring Boot创建的胖罐子文件。

    • 如果您已经创建了构建工件并且不愿意或不愿重建应用程序,则此选项非常有效。依赖项将被解开为/BOOT/libs/
  • 在构建工具中使用插件,将依赖项复制到特定文件夹中。

    • 在Maven中,可以使用maven-dependency-plugin来实现这一点。在下面的示例中,在Maven完成包装阶段后,依赖项将复制到/target/dependency文件夹。







 org.apache.maven.plugins
 maven-dependency-plugin
 3.1.2


 copy-dependencies
 package

 copy-dependencies



 ${project.build.directory}/dependency









使用自定义Java运行时构建Docker图像

现在,让我们组合JDEPS和JLINK来构建自定义的Java运行时。使用此运行时,我们可以为Spring Boot应用程序创建一个完美的,最小的Docker映像。

FROM maven:3-eclipse-temurin-17 as build
RUN mkdir /usr/src/project
COPY . /usr/src/project
WORKDIR /usr/src/project
RUN mvn package -DskipTests
RUN jar xf target/JavaCoffeeShop.jar
RUN jdeps --ignore-missing-deps -q  \
    --recursive  \
    --multi-release 17  \
    --print-module-deps  \
    --class-path 'BOOT-INF/lib/*'  \
    target/JavaCoffeeShop.jar > deps.info
RUN jlink \
    --add-modules $(cat deps.info) \
    --strip-debug \
    --compress 2 \
    --no-header-files \
    --no-man-pages \
    --output /myjre
FROM debian:bookworm-slim
ENV JAVA_HOME /user/java/jdk17
ENV PATH $JAVA_HOME/bin:$PATH
COPY --from=build /myjre $JAVA_HOME
RUN mkdir /project
COPY --from=build /usr/src/project/target/JavaCoffeeShop.jar /project/
WORKDIR /project
ENTRYPOINT java -jar JavaCoffeeShop.jar

在上面的示例中,我利用了多阶段的构建。初始建筑阶段基于eclipse-temurin JDK 17包含Maven的图像。这个阶段用于:

  • 创建Java伪像。使用maven,我创建包含完整应用程序的胖可执行罐文件。
  • 解开JAR文件以具有所有依赖关系。仅在不如前面所述的情况下使用maven-dependency-plugin时才需要。如果包括在内,则可以跳过此步骤
  • 使用JDEP获取必要的模块。指向包含所有依赖关系JAR文件和最终伪像的文件,并将列表保存在deps.info中。
  • 运行jlink以创建自定义的Java运行时。使用deps.info作为输入并将其存储在/myjre中。我们仅添加jlink并删除调试信息,手册页和标题文件所需的模块。

第二个也是最后一个阶段基于debian:stable-slim图像构建生产图像。

  • 设置环境变量。将JAVA_HOME设置为路径i ll复制myjre,然后将JAVA_HOME添加到PATH
  • 复制Jlink创建的Java运行时。引用第一阶段,然后将自定义Java运行时复制到定义为JAVA_HOME的位置。
  • 复制创建的Java工件。创建的脂肪可执行式弹头罐被复制到专用项目目录。
  • 设置入口点

Jlink在为Spring Boot Java应用程序创建Docker Images时提供了几个优点:

  1. 缩小图像大小:,如前所述,JLink可以帮助减少码头图像的大小,从而更快地部署和降低存储成本。

  2. 更快的启动时间:较小的Docker映像意味着您的应用程序可以更快地启动,这对于需要快速扩展的应用程序至关重要。

  3. 安全:仅包括必要的模块,您可以减少应用程序的攻击表面。较少的模块意味着更少的潜在安全漏洞。

说到安全性,必须提及Snyk在确保应用程序安全性方面的作用。 Snyk是一个开发人员安全工具,可以扫描源代码,开源软件包,容器图像和云配置的漏洞。使用SNYK容器和SNYK开源,您可以在应用程序及其依赖项中检测和修复安全问题,包括Docker Images中的安全性问题。

$ snyk container test your-repo/your-image:tag

在上述命令中,your-repo/your-image:tag是您的docker映像。 Snyk将扫描并报告任何检测到的漏洞,以及有关如何修复它们的建议。

为Java应用程序创建较小,更安全的Docker图像

请注意,此博客文章中的示例旨在展示如何使用Jlink为您的Java项目创建更简洁的Docker映像。显示的示例不符合安全码头图像的所有最佳实践。如果您想进一步了解这一点,请查看我们的10 best practices to build a Java container with Docker文章以获取一些灵感。

总而言之,JLINK是一种功能强大的工具,可以帮助您为Spring Boot Java应用程序创建较小,更安全的Docker映像。再加上SNYK等安全工具,您可以确保应用程序是性能和安全的。那么,为什么要等?立即注册SNYK并开始确保您的申请。