Spring Docker容器启动报错:No compatible attachment provider is available
问题描述
我正尝试将Spring Boot项目从2.6.7版本升级至3.1.1版本。项目主函数使用了reactor-tools中的ReactorDebugAgent,代码如下:
public static void main(String[] args) { ReactorDebugAgent.init(); SpringApplication.run(MyApplication.class, args); }
该部分代码在升级过程中未做修改。项目在本地运行正常,但通过mvn clean package spring-boot:build-image -B构建容器镜像后,容器无法启动,报错信息如下:
Exception in thread "main" java.lang.reflect.InvocationTargetException at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.base/java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49) at org.springframework.boot.loader.Launcher.launch(Launcher.java:95) at org.springframework.boot.loader.Launcher.launch(Launcher.java:58) at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:65) Caused by: java.lang.IllegalStateException: No compatible attachment provider is available at reactor.tools.shaded.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:632) at reactor.tools.shaded.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:616) at reactor.tools.shaded.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:568) at reactor.tools.shaded.net.bytebuddy.agent.ByteBuddyAgent.install(ByteBuddyAgent.java:545) at reactor.tools.agent.ReactorDebugAgent.init(ReactorDebugAgent.java:56) at com.maersk.publictracking.MyApplication.main(MyApplication.java:14) ... 8 more
使用的Java版本:17
项目pom.xml内容如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.1.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.acme</groupId> <artifactId>my-application</artifactId> <version>0.0.81</version> <name>my-application</name> <description>my-application</description> <properties> <io-grpc-netty.version>1.55.1</io-grpc-netty.version> <jacoco.version>0.8.10</jacoco.version> <java.version>17</java.version> <maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version> <shared-error-handling-lib.version>3.1.0</shared-error-handling-lib.version> <spring-cloud-sleuth-otel.dependencies.version>1.1.3</spring-cloud-sleuth-otel.dependencies.version> <spring-cloud.version>2021.0.6</spring-cloud.version> <testcontainers.version>1.18.1</testcontainers.version> <tests.skip>false</tests.skip> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <exclusions> <exclusion> <artifactId>logback-classic</artifactId> <groupId>ch.qos.logback</groupId> </exclusion> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-sleuth</artifactId> <exclusions> <exclusion> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-brave</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-otel-autoconfigure</artifactId> </dependency> <dependency> <groupId>io.opentelemetry</groupId> <artifactId>opentelemetry-exporter-otlp</artifactId> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${io-grpc-netty.version}</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>io.micrometer</groupId> <artifactId>micrometer-registry-prometheus</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j2</artifactId> </dependency> <dependency> <groupId>com.acme.shared</groupId> <artifactId>error-handling</artifactId> <version>${shared-error-handling-lib.version}</version> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>elasticsearch</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>junit-jupiter</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-tools</artifactId> </dependency> <dependency> <groupId>io.projectreactor</groupId> <artifactId>reactor-test</artifactId> <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-sleuth-otel-dependencies</artifactId> <version>${spring-cloud-sleuth-otel.dependencies.version}</version> <scope>import</scope> <type>pom</type> </dependency> <dependency> <groupId>org.testcontainers</groupId> <artifactId>testcontainers-bom</artifactId> <version>${testcontainers.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <release>17</release> <forceJavacCompilerUse>true</forceJavacCompilerUse> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>versions-maven-plugin</artifactId> <version>${versions-maven-plugin.version}</version> <configuration> <rulesUri>file:///${basedir}//versions-rules.xml</rulesUri> </configuration> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco.version}</version> <configuration> <excludes> <exclude>com/foo/myapplication/models/**/*</exclude> </excludes> </configuration> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>default-report</id> <phase>prepare-package</phase> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>${maven-surefire-plugin.version}</version> <configuration> <skipTests>${tests.skip}</skipTests> </configuration> </plugin> </plugins> </build> <repositories> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </repository> <repository> <id>github</id> <url>https://maven.pkg.github.com/acme-global/*</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> </pluginRepository> </pluginRepositories> </project>
解决方案
核心原因:Spring Boot Build Image默认使用的精简JRE镜像缺少ReactorDebugAgent(依赖ByteBuddy Agent)所需的JDK附件模块,本地用完整JDK所以正常,容器镜像默认仅包含运行时JRE导致报错。
方案1:指定容器使用完整JDK镜像
修改spring-boot-maven-plugin配置,强制构建镜像时使用包含完整JDK的基础镜像:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <image> <builder>paketobuildpacks/builder-jammy-full:latest</builder> <env> <BP_JVM_VERSION>17</BP_JVM_VERSION> <BP_JVM_TYPE>jdk</BP_JVM_TYPE> </env> </image> </configuration> </plugin>
修改后重新执行mvn clean package spring-boot:build-image -B构建镜像即可。
方案2:添加JVM启动参数允许Agent附加
如果不想切换到JDK镜像,可在容器启动时添加允许Agent自我附加的参数:
java -Djdk.attach.allowAttachSelf=true -jar your-app.jar
或者在spring-boot-maven-plugin中配置默认启动参数:
<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <image> <env> <BP_JVM_VERSION>17</BP_JVM_VERSION> <BPE_APPEND_JAVA_TOOL_OPTIONS>-Djdk.attach.allowAttachSelf=true</BPE_APPEND_JAVA_TOOL_OPTIONS> </env> </image> </configuration> </plugin>
方案3:调整ReactorDebugAgent的初始化逻辑
通过系统属性控制Agent的启用,避免启动时强制初始化:
public static void main(String[] args) { if (Boolean.getBoolean("reactor.tools.agent.enabled")) { ReactorDebugAgent.init(); } SpringApplication.run(MyApplication.class, args); }
之后在容器启动时添加参数-Dreactor.tools.agent.enabled=true,或在镜像构建时配置对应环境变量。
内容的提问来源于stack exchange,提问作者Jimmy Foobar
相关产品推荐
相关产品推荐

