spring-attic / spring-native

Spring Native is now superseded by Spring Boot 3 official native support
https://docs.spring.io/spring-boot/docs/current/reference/html/native-image.html
Apache License 2.0
2.74k stars 355 forks source link

Combine the tracing agent of graalvm and spring aot plugin #1651

Closed mpumd closed 2 years ago

mpumd commented 2 years ago

Hi everyone,

I'm currently test some migrates of business spring boot applications for a company. After 4 weeks, I found a best way to have a satisfactory result with combine the tracing agent of graalvm and the plugin aot of spring native.

configuration :

I use a sequence of two differents maven lifecycle like following :

mvn clean test -Ptracing-agent && mvn spring-boot:build-image -DskipTests -P'nativeImage,aot-generate'  

The tracing agent is activated during a integration test which call all endpoints. Using a real infrastructure seems to be important during the test. For example, use h2 instead of oracle db could causes a runtime fail when you change configuration to target oracle.

<profile>
    <id>tracing-agent</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.experimental</groupId>
                <artifactId>spring-aot-maven-plugin</artifactId>
                <version>${spring-native.version}</version>
                <configuration>
                    <mode>native-agent</mode>
                    <debugVerify>true</debugVerify>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <configuration>
                    <argLine>-agentlib:native-image-agent=access-filter-file=access-filter.json,config-merge-dir=target/classes/META-INF/native-image</argLine>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>
<profile>
    <id>aot-generate</id>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.experimental</groupId>
                <artifactId>spring-aot-maven-plugin</artifactId>
                <version>${spring-native.version}</version>
                <configuration>
                    <debugVerify>true</debugVerify>
                </configuration>
                <executions>
                    <execution>
                        <id>generate</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</profile>
<profile>
    <id>nativeImage</id>
    <properties>
        <paketo.builder.image>tiny</paketo.builder.image> <!-- full, base, tiny -->
        <repackage.classifier/>
        <native.image.build.arguments/>
        <enable-apm>false</enable-apm>
    </properties>
    <!-- ... certificates binding mecanics plugin -->
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <classifier>${repackage.classifier}</classifier>
                    <image>
                        <builder>paketobuildpacks/builder:${paketo.builder.image}</builder>
                        <env>
                            <BP_NATIVE_IMAGE>true</BP_NATIVE_IMAGE>
                            <BP_NATIVE_IMAGE_BUILD_ARGUMENTS>${native.image.build.arguments}</BP_NATIVE_IMAGE_BUILD_ARGUMENTS>
                            <BP_JVM_VERSION>11</BP_JVM_VERSION>
                            <BP_IMAGE_LABELS>name="my-image"</BP_IMAGE_LABELS>
                            <BPE_TZ>Europe/Zurich</BPE_TZ>
                            <BPE_CHARSET>UTF-8</BPE_CHARSET>
                            <BPE_LANGUAGE>fr_CH.UTF-8</BPE_LANGUAGE>
                            <BPE_LANG>fr_CH.UTF-8</BPE_LANG>
                            <BPE_LC_ALL>fr_CH.UTF-8</BPE_LC_ALL>
                        </env>
                        <bindings>
                            <binding>${project.build.directory}/bindings/ca-certificates:/platform/bindings/ca-certificates</binding>
                        </bindings>
                    </image>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.springframework.experimental</groupId>
            <artifactId>spring-native</artifactId>
        </dependency>
    </dependencies>

    <!-- Repositories temporarily required for spring-native artifacts -->
    <repositories>
        <repository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/release</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/release</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</profile>

If I use only the spring aot plugin, I have the following issue at runtime of the native image packaged inside docker image :

13:29:43.074 [main] DEBUG org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter - Application failed to start due to an exception
java.lang.ClassNotFoundException: org.springframework.cloud.vault.config.VaultConfigDataLocationResolver
        at java.lang.Class.forName(DynamicHub.java:1121)
        at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
        at org.springframework.boot.util.Instantiator$TypeSupplier$1.get(Instantiator.java:232)
        at org.springframework.boot.util.Instantiator.instantiate(Instantiator.java:147)
        ...

Native reflection configuration for org.springframework.cloud.vault.config.VaultConfigDataLocationResolver is missing.

Using the tracing-agent only causes a compilation error on the native build.

[INFO]     [creator]     Fatal error: org.graalvm.compiler.debug.GraalError: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.springframework.util.unit.DataSize are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=org.springframework.util.unit.DataSize.
...
[INFO]     [creator]     Caused by: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: No instances of org.springframework.util.unit.DataSize are allowed in the image heap as this class should be initialized at image runtime. To see how this object got instantiated use --trace-object-instantiation=org.springframework.util.unit.DataSize.

So what do you think about my solution ? Thanks.

sdeleuze commented 2 years ago

I guess you are missing some bits but the principle makes sense, and unless I am mistaken that what we will achieve via https://github.com/spring-projects-experimental/spring-native/issues/1247 that is about to be fixed with the upcoming NBT 0.9.13 release. This will be less error prone and much easier to use.

Please check our updated docs and *-agent samples when Spring Native 0.12.1 will be released, and reopen or comment here if that does not work for your use case.