Skip to content

Instantly share code, notes, and snippets.

@snicoll
Last active November 22, 2022 10:26
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save snicoll/4ac487e2b671100647d8cb42ca05ae0e to your computer and use it in GitHub Desktop.
Save snicoll/4ac487e2b671100647d8cb42ca05ae0e to your computer and use it in GitHub Desktop.

Current status

Single module with Cloud Native Buildpacks

mvn spring-boot:build-image -Pnative

This works, even if the Spring Boot Maven Plugin nor the Native Build Tools Plugin have been applied in the project as the native profile brings them.

It should be noted that repackage runs for the reason above.

Single module with Native Build Tools

 mvn native:compile -Pnative

This works, even if the Spring Boot Maven Plugin nor the Native Build Tools Plugin have been applied in the project as the native profile brings them.

Multi modules with Cloud Native Buildpacks

We know this command will never work with a multi-modules project

mvn spring-boot:build-image -Pnative

We can see that the reachability metadata is running on the root POM.

We can see that it fails early as process AOT is trying to run on the root pom.

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-buildpacks                                                   [pom]
[INFO] multi-buildpacks-lib                                               [jar]
[INFO] multi-buildpacks-app                                               [jar]
[INFO]
[INFO] ---------------< com.example.multinbt:multi-buildpacks >----------------
[INFO] Building multi-buildpacks 0.0.1-SNAPSHOT                           [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks >>>
[INFO]
[INFO] --- native-maven-plugin:0.9.17:add-reachability-metadata (add-reachability-metadata) @ multi-buildpacks ---
[INFO] Downloaded GraalVM reachability metadata repository from file:/Users/snicoll/.m2/repository/org/graalvm/buildtools/graalvm-reachability-metadata/0.9.17/graalvm-reachability-metadata-0.9.17-repository.zip
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) @ multi-buildpacks ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-buildpacks 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-buildpacks ................................... FAILURE [  0.877 s]
[INFO] multi-buildpacks-lib ............................... SKIPPED
[INFO] multi-buildpacks-app ............................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.286 s
[INFO] Finished at: 2022-11-21T10:12:10+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) on project multi-buildpacks: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Multi modules with Native Build Tools

We know this command will never work with a multi-modules project

mvn native:compile -Pnative

We can see that the reachability metadata is running on the root POM.

We can see that it fails early as process AOT is trying to run on the root pom.

[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-nbt                                                          [pom]
[INFO] multi-nbt-lib                                                      [jar]
[INFO] multi-nbt-app                                                      [jar]
[INFO]
[INFO] -------------------< com.example.multinbt:multi-nbt >-------------------
[INFO] Building multi-nbt 0.0.1-SNAPSHOT                                  [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> native-maven-plugin:0.9.17:compile (default-cli) > package @ multi-nbt >>>
[INFO]
[INFO] --- native-maven-plugin:0.9.17:add-reachability-metadata (add-reachability-metadata) @ multi-nbt ---
[INFO] Downloaded GraalVM reachability metadata repository from file:/Users/snicoll/.m2/repository/org/graalvm/buildtools/graalvm-reachability-metadata/0.9.17/graalvm-reachability-metadata-0.9.17-repository.zip
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) @ multi-nbt ---
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-nbt 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-nbt .......................................... FAILURE [  1.109 s]
[INFO] multi-nbt-lib ...................................... SKIPPED
[INFO] multi-nbt-app ...................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.901 s
[INFO] Finished at: 2022-11-21T10:13:42+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:process-aot (process-aot) on project multi-nbt: Unable to find a suitable main class, please add a 'mainClass' property -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

Summary

The current arrangement is a bit unusual as triggering the profile enables the actual execution of two plugins, regardless of the nature of the module. The Spring Boot Maven Plugin and the Native Build Tools plugin are applied on all modules, which makes a setup with a multi-modules project impossible.

Proposal

The obvious proposal is to move everything to pluginManagement so that things are only applied if the related plugin is in use. As we will see, this has some side effects.

Single module with Cloud Native Buildpacks

mvn spring-boot:build-image -Pnative

This runs and fails as process AOT didn't run at all. The project above was wrong to begin with as it didn't apply the Spring Boot Maven plugin at all, something that is to be expected for a Spring Boot app.

If we add the Spring Boot Maven Plugin, this looks like it works but it really isn't as the reachability metadata has not been fetched. Adding a reference to the native build tools plugin fixes this.

Single module with Native Build Tools

mvn native:compile -Pnative

This runs and fails as process AOT didn't run at all. The project above was wrong to begin with as it didn't apply the Spring Boot Maven plugin at all, something that is to be expected for a Spring Boot app.

If we add the Spring Boot Maven Plugin, it works. We can see that the additional execution of the NBT metadata goal does not run, as we have triggered a goal of the native plugin, but not configured the actual plugin to contribute whatever the parent and/or a profile can do.

It works because, in the absence of metadata, the compile goal is going to fetch it. That looks like some sort of fallback that's welcome for this particular case.

Multi modules with Cloud Native Buildpacks

The command below still fails but it makes much more sense now.

mvn spring-boot:build-image -Pnative
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-buildpacks                                                   [pom]
[INFO] multi-buildpacks-lib                                               [jar]
[INFO] multi-buildpacks-app                                               [jar]
[INFO]
[INFO] ---------------< com.example.multinbt:multi-buildpacks >----------------
[INFO] Building multi-buildpacks 0.0.1-SNAPSHOT                           [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks >>>
[INFO]
[INFO] <<< spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) < package @ multi-buildpacks <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) @ multi-buildpacks ---
[INFO]
[INFO] -------------< com.example.multinbt:multi-buildpacks-lib >--------------
[INFO] Building multi-buildpacks-lib 0.0.1-SNAPSHOT                       [2/3]
[INFO] --------------------------------[ jar ]---------------------------------
[INFO]
[INFO] >>> spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) > package @ multi-buildpacks-lib >>>
[INFO]
[INFO] --- maven-resources-plugin:3.3.0:resources (default-resources) @ multi-buildpacks-lib ---
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/main/resources
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/main/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:compile (default-compile) @ multi-buildpacks-lib ---
[INFO] Changes detected - recompiling the module!
[INFO] Compiling 1 source file to /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/target/classes
[INFO]
[INFO] --- maven-resources-plugin:3.3.0:testResources (default-testResources) @ multi-buildpacks-lib ---
[INFO] skip non existing resourceDirectory /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/src/test/resources
[INFO]
[INFO] --- maven-compiler-plugin:3.10.1:testCompile (default-testCompile) @ multi-buildpacks-lib ---
[INFO] No sources to compile
[INFO]
[INFO] --- maven-surefire-plugin:2.22.2:test (default-test) @ multi-buildpacks-lib ---
[INFO] No tests to run.
[INFO]
[INFO] --- maven-jar-plugin:3.3.0:jar (default-jar) @ multi-buildpacks-lib ---
[INFO] Building jar: /Users/snicoll/workspace/work/spring-aot-smoke-tests/boot/maven-parent/multi-buildpacks/multi-buildpacks-lib/target/multi-buildpacks-lib-0.0.1-SNAPSHOT.jar
[INFO]
[INFO] <<< spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) < package @ multi-buildpacks-lib <<<
[INFO]
[INFO]
[INFO] --- spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) @ multi-buildpacks-lib ---
[INFO] Building image 'docker.io/library/multi-buildpacks-lib:0.0.1-SNAPSHOT'
[INFO]
[INFO]  > Pulling builder image 'docker.io/paketobuildpacks/builder:tiny' 100%
[INFO]  > Pulled builder image 'paketobuildpacks/builder@sha256:97038c4c8b0907b1084526a409cdc29010d690e56ee789eca5d369a6c55ef128'
[INFO]  > Pulling run image 'docker.io/paketobuildpacks/run:tiny-cnb' 100%
[INFO]  > Pulled run image 'paketobuildpacks/run@sha256:6edd2f36f33b08a4553449b91cd4f4d4bcffd1c8d7677b35790d1b80fa13720c'
[INFO]  > Executing lifecycle version v0.15.1
[INFO]  > Using build cache volume 'pack-cache-3361f01b477e.build'
[INFO]
[INFO]  > Running creator
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-buildpacks 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-buildpacks ................................... SUCCESS [  0.479 s]
[INFO] multi-buildpacks-lib ............................... FAILURE [  3.774 s]
[INFO] multi-buildpacks-app ............................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  4.993 s
[INFO] Finished at: 2022-11-21T10:55:14+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image (default-cli) on project multi-buildpacks-lib: Execution default-cli of goal org.springframework.boot:spring-boot-maven-plugin:3.0.0-SNAPSHOT:build-image failed: Error packaging archive for image: Unable to find main class -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException
[ERROR]
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <args> -rf :multi-buildpacks-lib

build image is applied on a library, which does not have a main class and should not be considered.

To fix this in a multi-modules project, we need to opt-in to whatever we want to use to build the image. This can be done by adding the specified profile in the app module:

<profile>
	<id>native</id>
	<build>
		<plugins>
			<plugin>
				<groupId>org.graalvm.buildtools</groupId>
				<artifactId>native-maven-plugin</artifactId>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>build-image</id>
						<goals>
							<goal>build-image</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</profile>

The image can be created as follows (from the root, as usual):

mvn package -Pnative

Multi modules with Native Build Tools

The command below still fails

mvn native:compile -Pnative
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Build Order:
[INFO]
[INFO] multi-nbt                                                          [pom]
[INFO] multi-nbt-lib                                                      [jar]
[INFO] multi-nbt-app                                                      [jar]
[INFO]
[INFO] -------------------< com.example.multinbt:multi-nbt >-------------------
[INFO] Building multi-nbt 0.0.1-SNAPSHOT                                  [1/3]
[INFO] --------------------------------[ pom ]---------------------------------
[INFO]
[INFO] >>> native-maven-plugin:0.9.17:compile (default-cli) > package @ multi-nbt >>>
[INFO]
[INFO] <<< native-maven-plugin:0.9.17:compile (default-cli) < package @ multi-nbt <<<
[INFO]
[INFO]
[INFO] --- native-maven-plugin:0.9.17:compile (default-cli) @ multi-nbt ---
[INFO] Found GraalVM installation from JAVA_HOME variable.
[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary for multi-nbt 0.0.1-SNAPSHOT:
[INFO]
[INFO] multi-nbt .......................................... FAILURE [  0.695 s]
[INFO] multi-nbt-lib ...................................... SKIPPED
[INFO] multi-nbt-app ...................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.494 s
[INFO] Finished at: 2022-11-21T11:04:45+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.graalvm.buildtools:native-maven-plugin:0.9.17:compile (default-cli) on project multi-nbt: Image classpath is empty. Check if your classpath configuration is correct. -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoExecutionException

This is better as the error message is directly linked to the goal that was used. Our native profile doesn't go in the way anymore.

Same thing as Buildpacks, we want to identify the module where running this goal makes sense and use the package phase. This profile does the trick

<profile>
	<id>native</id>
	<build>
		<plugins>
			<plugin>
				<groupId>org.graalvm.buildtools</groupId>
				<artifactId>native-maven-plugin</artifactId>
				<executions>
					<execution>
						<id>build-image</id>
						<goals>
							<goal>compile-no-fork</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
	</build>
</profile>

Summary

Not applying the plugins unless they have been specified makes the multi-modules arrangeement more idiomatic. It makes the user experience for single module a bit harder as you need to apply an extra plugin. It makes it more obvious though that Buildpacks relies on NBT to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment