无需Dockerfile构建Java容器:Azul Zulu与Paketo Buildpacks
目录
这是 Azul Zulu Docker 官方镜像系列的第 5 篇文章:
- 值得信赖的 Java 容器:Azul Zulu OpenJDK 加入 Docker 官方镜像
- Java 的 Docker 官方镜像之路:Azul Zulu 的故事
- 使用 Azul Zulu Docker 官方镜像:从简单拉取到精简容器
- 所有 Azul Zulu 容器镜像详解:CA、SA 和 Chainguard
到目前为止,本系列每篇文章都展示了 Dockerfile:选择一个基础镜像,复制一个 JAR 文件,设置入口点,然后交付。这种方式行之有效。但 Spring Boot 开发者通常完全跳过 Dockerfile,仍然能通过 Paketo 构建包获得使用 Azul Zulu 作为 JVM 的生产就绪容器。下面是它的工作原理以及如何配置。
什么是 Paketo 构建包?
Paketo 构建包 实现了 Cloud Native Buildpacks (CNB) 规范。构建包不需要 Dockerfile,而是检查你的应用程序源代码,判断运行所需的内容,并组装一个分层的 Open Container Initiative (OCI) 镜像。一个层提供 JVM(Azul Zulu),另一个层编译并打包 Java 应用,其他层添加启动辅助工具。每个关注点保持独立,并可单独更新。
Paketo Java 构建包 处理 Java 应用所需的一切:依赖下载、编译、分层、JVM 注入和启动配置。JVM 本身来自一个独立的、可替换的构建包。Paketo Azul Zulu 构建包(构建包 ID:paketo-buildpacks/azul-zulu)使用 Azul Zulu OpenJDK 构建提供该 JVM 层。该构建包由 Paketo 维护,Daniel Mikusa 做出了重要贡献。最新的 Zulu 版本(出自 '26 年 4 月的安全更新)在其发布后的 3 天内就被集成到了 Paketo 中。
Spring Boot 已在使用 Paketo
如果你使用 Spring Boot Maven 插件并运行 spring-boot:build-image,Paketo 会完成所有工作。该插件默认调用 paketobuildpacks/builder:base 构建器。要使用 Azul Zulu,你需要在构建包列表中,将 paketobuildpacks/azul-zulu 添加到 paketobuildpacks/java 之前。这个顺序很重要,因为 Paketo 会使用第一个匹配的 JVM 构建包。
设置演示项目
本文中的代码示例可在 FDelporte/azul-paketo-demo 获得。该目录包含一个最小的 Spring Boot 应用程序,你可以自行运行。
该应用程序只有一个 REST 端点:
pom.xml 添加了 Spring Boot 的 Web 启动器和 Maven 插件:
使用一条命令构建容器镜像:
输出显示 Azul Zulu 构建包下载并配置 JVM:
创建的镜像大小如下:
运行它并通过 REST 端点检查 Java 版本:
或者检查 Docker 输出中的 Spring 日志:
配置 Azul Zulu 构建包
Paketo 构建包接受两类环境变量:构建时配置(前缀 BP_)和运行时配置(前缀 BPL_)。你在 spring-boot-maven-plugin 配置的 <env> 块中设置它们。
选择 Java 版本和类型
你可以指定 Java 版本和运行时类型。将 BP_JVM_TYPE 设置为 JDK 会在运行时镜像中保留完整的 JDK。当你的应用程序需要 JDK 独有工具(如 jmap 或 jstack)时,这很有用,但会增加镜像体积,并为生产容器添加不必要的工具。除非有特殊原因,否则请使用 JRE。
使用 jlink 生成自定义 JRE
Azul Zulu 构建包通过 BP_JVM_JLINK_ENABLED 变量在构建时支持 jlink。启用后,构建包会运行 jlink 生成一个仅包含应用程序使用的 Java 模块的最小 JRE:
正如本系列前一篇文章所示,jlink 将典型容器镜像从 ~370 MB(JRE)缩小到 ~140 MB(自定义运行时)。构建包会自动为你处理 jdeps 和 jlink 步骤。
Spring Boot 应用注意事项: Spring Boot 依赖反射和类路径扫描。jlink 在构建时可能遗漏必要的模块。在生产环境中使用 BP_JVM_JLINK_ENABLED=true 之前,请充分测试生成的容器。
仓库中示例项目创建的容器大小为 136 MB:
启用可观测性和调试功能
构建包可以使用 BPE_DEFAULT_ 前缀的环境变量将可观测性配置烘焙到镜像中。这些变量为 BPL_ 运行时标志设置默认值,而无需容器运行者显式传递它们。
以下示例启用了 Java Flight Recording、远程调试和 JMX,适用于 staging 环境的配置:
有关这些调试选项的完整介绍以及如何在运行中的容器内验证它们,请参阅之前的文章:配置 Spring Boot 以使用 Azul Zulu 和调试选项构建 Docker 镜像。
不出所料,包含完整 JDK 会增加容器大小。在这种情况下,我们还需要添加额外的端口来暴露调试功能:
完整配置参考
有关 BP_ 和 BPL_ 变量的完整最新列表,请参阅 paketo-buildpacks/azul-zulu 的 GitHub README 中的“Configuration”部分。
在没有 Spring Boot 的情况下使用 Paketo
Paketo 并非 Spring Boot 专属。你可以直接使用 pack CLI 构建任何 JVM 应用程序。
从 buildpacks.io 安装 pack,然后运行以下命令。在此示例中,我们复用了 Spring Boot 演示中已编译的 jar 文件:
这会生成一个 OCI 镜像,使用最新的 Azul Zulu 作为 JVM(当前版本 26),并附带 Spring Boot 插件所使用的相同内存计算器、NMT 和启动辅助工具。
如果我们想坚持使用 JVM 25 并使用 jlink,可以通过 --env 传递构建时环境变量:
容器大小
根据仓库中的示例,创建了以下容器大小:
显然,Spring Boot 和 pack 生成的容器大小相当。## Paketo 使用的是哪个 Zulu 镜像?
如 paketo-buildpacks/azul-zulu 中的 buildpack.toml 文件所示,使用了 Azul Zulu Builds of OpenJDK 的 .tar.gz 社区可用性(CA)版本。这些文件直接从 Azul 的 CDN 拉取。Azul Zulu CA 可免费下载和使用。正如 All Azul Zulu Container Images Explained 中所解释的,CA 是开发、开源项目以及不需要商业支持合同的部署的正确选择。
这对你的构建流水线意味着什么
Paketo 和基于 Dockerfile 的构建解决了不同的问题。Dockerfile 构建让你完全控制每一层。Paketo 构建则提供自动内存调优、NMT、JFR 钩子以及一个无需维护 Dockerfile 的正确分层的镜像。
对于 Spring Boot 团队,只需进行少量配置更改即可将 Azul Zulu 用作运行时 JVM。对于想要明确控制 Java 版本或运行时类型的团队,请使用 BP_JVM_VERSION 和 BP_JVM_TYPE 变量。
示例代码位于 FDelporte/azul-paketo-demo。尝试最小示例,比较镜像大小,看看哪种方法最适合你的流水线。
本系列之前的文章:
- 可靠的 Java 容器:Azul Zulu OpenJDK 加入 Docker 官方镜像
- Java 的 Docker 官方镜像之路:Azul Zulu 的故事
- 使用 Azul Zulu Docker 官方镜像:从简单拉取到精简容器
- 所有 Azul Zulu 容器镜像详解:CA、SA 和 Chainguard
相关文章:
本文 无需 Dockerfile 构建 Java 容器:Azul Zulu 和 Paketo 构建包 首次出现在 foojay 上。