[spring-projects/spring-boot]bootBuildImage 在 buildpack 版本更新后停止工作?

2024-04-12 320 views
7

很抱歉提出有关此问题的问题,但我找不到任何可以解决此问题的文档:

本周早些时候,我们正在使用gradle bootBuildImage --imageName=....但突然我们的部署停止工作了。我们刚刚合并了对 Reactor 的 BlockHound 的支持,并收到一个错误,该错误归结为:

Caused by: java.lang.IllegalStateException: No compatible attachment provider is available

然后我注释掉了,BlockHound.install()但现在我们的部署仍然触发了错误:

Unrecognized option: -server

然后我检查了我们的构建日志,并注意到之前的工作构建使用了:

 > Running creator
    [creator]     ===> DETECTING
    [creator]     5 of 16 buildpacks participating
    [creator]     paketo-buildpacks/bellsoft-liberica 2.13.0
    [creator]     paketo-buildpacks/executable-jar    2.1.1
    [creator]     paketo-buildpacks/apache-tomcat     1.5.0
    [creator]     paketo-buildpacks/dist-zip          1.4.0
    [creator]     paketo-buildpacks/spring-boot       2.5.0

而新的失败者则使用:

 > Running creator
    [creator]     ===> DETECTING
    [creator]     5 of 17 buildpacks participating
    [creator]     paketo-buildpacks/bellsoft-liberica 3.2.0
    [creator]     paketo-buildpacks/executable-jar    3.1.0
    [creator]     paketo-buildpacks/apache-tomcat     2.2.0
    [creator]     paketo-buildpacks/dist-zip          2.2.0
    [creator]     paketo-buildpacks/spring-boot       3.1.0

我现在假设版本提升与我们的应用程序不兼容?我可以更改一些设置以恢复到旧的构建包吗?或者也许强制它在内部使用 JDK(这就是 BlockHound 错误似乎涉及的问题)?

回答

1

如果有人遇到同样的问题:

通过退回到更手动的方法来修复它:

将 Dockerfile 添加到您的存储库

FROM adoptopenjdk:8-jdk-hotspot as builder
WORKDIR application
ARG JAR_FILE=build/libs/app.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract

FROM adoptopenjdk:8-jdk-hotspot
WORKDIR application
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]

(根据你的喜好使用 jdk/jre,我切换到 jdk 因为我想让 BlockHound 工作。)

然后将您的bootJar任务配置为使用图层并用作app.jar存档名称:

tasks.getByName<BootJar>("bootJar") {
    archiveFileName.value("app.jar")
    layered()
}

现在不要运行bootBuildImagebootJar而是像这样运行并构建 docker 映像:

docker build . --tag=...

我喜欢这样,这样我可以拥有更多的控制权。在我的 CI/CD 流程中,我不喜欢在背后构建不断变化的依赖项。

1

@jgrgt 我刚刚复制了这个,我将与 BlockHound 团队合作找出这个故事是什么。

0

@jgrgt 你能描述一下传递给构建的参数周围的任何其他配置吗?具体来说,您是否知道-server错误可能来自何处以及实际来自何处?

8

ByteBuddy 中似乎存在问题,仅使用net.bytebuddy:byte-buddy-agent:1.10.14ByteBuddyAgent.install();使其以同样的方式失败(cc @raphw)。

这是 @nebhale 的重现器: https://github.com/nebhale/BOOT-23121 克隆后,./gradlew bootBuildImage --imageName=applications/gradle-demo && docker run applications/gradle-demo:latest将出现问题中描述的故障。

但是,添加net.java.dev.jna:jna-platform:5.6.0会启用模拟附件策略并使其正确启动。

1

感谢您查看这个!

@nebhale我检查了我们的基础代码,它-server位于 JAVA_OPTS 环境变量中。对不起!这曾经有效,但现在不再适用于bootBuildImage.但这当然可以在我们这边改变。

@bsideup 我可以确认添加implementation("net.java.dev.jna:jna-platform:5.6.0")到我的依赖项可以使 BlockHound 问题消失。谢谢!

4

啊,是的,-server现在真是一个奇怪的选择。一点背景:

java -cp "${CLASSPATH}" ${JAVA_OPTS} <Main-Class>以前我们会使用诸如启动应用程序之类的命令。不幸的是,我们有多个用户遇到问题,通过 可靠地将标志获取${JAVA_OPTS}到可能在容器内运行的各种 Java 进程中。为了解决这个问题,我们决定依赖现代 JVM 中内置的两个功能:

  1. ${CLASSPATH}从环境中读取作为替代-cp
  2. ${JAVA_TOOL_OPTIONS}从环境中读取作为命令行上标志的替代

我们现在创建的命令行java <Main-Class>非常棒,但不幸的是,似乎并非所有标志在${JAVA_TOOL_OPTIONS}.您可以在您的计算机上本地查看此示例:

➜ java -server -version
openjdk version "11.0.8" 2020-07-14 LTS
OpenJDK Runtime Environment (build 11.0.8+10-LTS)
OpenJDK 64-Bit Server VM (build 11.0.8+10-LTS, mixed mode)
➜ JAVA_TOOL_OPTIONS="-server" java -version
Picked up JAVA_TOOL_OPTIONS: -server
Unrecognized option: -server
Error: Could not create the Java Virtual Machine.
Error: A fatal exception has occurred. Program will exit.

${JAVA_OPTS}鉴于我们从到解决的问题数量${JAVA_TOOL_OPTIONS} 如此之大,我们不太可能再回去。事实上,-server此时在 64 位 Linux JVM 中会被忽略(而不是直接配置编译器标志)。如果设置非常重要-server,Java 9 及更高版本还有另一个标志,${JDK_JAVA_OPTIONS}允许您设置-server

0

但是,添加net.java.dev.jna:jna-platform:5.6.0会启用模拟附件策略并使其正确启动。

这是相当令人期待的。如果您使用 JRE 而没有完整的 JDK,则虚拟机 API 会丢失并且无法附加。当然,除非 Byte Buddy 可以自己完成附件,这需要本机适配器(JNA)。

4

@raphw 感谢您的回答!

我认为,在 Java 9+ 上,BB 在 JRE 上运行得很好?我很确定我已经看到它在 JRE 上运行得很好,无需 JNA...

8

从技术上讲,Java 9 中不再有 JRE。不过,有些人确实分发了“精简模块 JVM”,并将其称为 JRE。如果缺少jdk.attch模块,附件将不再工作,就像没有java.sql模块 JDBC 将无法工作一样。

请注意,java.instrument模块也是必需的且无法模拟。

3

@raphw 嗯,该模块确实丢失了:

$ java --list-modules | grep attach
$

看来Liberica排除了该模块,需要使用仿真。

谢谢你的帮助! ?

9

Liberica 分为 JDK 和“JRE”,其中 JRE 包含与 Java 8 的 JRE 规范最相似的模块。

6

@nebhale 感谢您对国旗的见解-server。我们不需要它,所以我们可以放弃它。

连同jna-platform依赖项我们现在可以bootBuildImage再次使用。

1

关闭这个问题,因为很明显它与 Paketo 构建包有关,而不是 Spring Boot 可以解决的问题。