0

I'm currently migrating to Spring boot 3.0. In the process, I'm looking into using the newly integrated Native support.

When using pack to build and publish my image, I get an error:

Executing native-image -H:+StaticExecutableWithDynamicLibC -jar /workspace 
Error: /workspace is a directory. (-jar requires a valid jarfile)

Apparently, the native-image buildpack is trying to use the folder instead of jar. I'm using this command to try to build the image.

 pack -v build ghcr.io/kevinbos-cc/buildpacks-demo:latest \
          --builder paketobuildpacks/builder:tiny \
          --path . \
          --env "BP_JVM_VERSION=17" \
          --env "BP_NATIVE_IMAGE=true" \
          --cache-image ghcr.io/kevinbos-cc/buildpacks-demo-paketo-cache-image:latest \
          --publish

I've tried to change the paketo-buildpacks/java-native-image version and to use paketo-buildpacks/graalvm. Unfortently these changes had the same result.

When running the ./gradle bootBuildImage the image is created just fine. But I can't figure out how to reproduce this in the pack command.

Full stack trace can be found here.

If someone could point me in the right direction, that would be great!

Kevin Bos
  • 173
  • 1
  • 12

1 Answers1

3

I believe you're hitting an issue between Spring/Gradle & Buildpacks that is fairly common.

I think it was in Spring Boot 2.7, a setting was changed that causes Gradle builds, by default, to produce both a boot-ified and regular JAR file. By itself, this isn't a problem, but buildpacks need to handle multiple JAR files differently than a single JAR file, and some things like a native-image build still only work with single JAR files.

I know for sure that your build is producing two JAR files, as I can see in the output you linked. It says this:

Restoring multiple artifacts

so that's a pretty good sign that you're hitting this issue.

The good news is that this is an easy fix. You just need to tell Gradle to only build the boot-ified JAR.

In your build.gradle set this:

jar {
    enabled = false
}

or build.gradle.kts:

tasks.getByName<Jar>("jar") {
    enabled = false
}

See here or here for Kotlin.

If that doesn't help, you may be hitting a bug. In that case, please open an issue here and post a sample to reproduce.

Daniel Mikusa
  • 13,716
  • 1
  • 22
  • 28
  • That's indeed the problem! Thank you for pointing it out! – Kevin Bos Dec 06 '22 at 08:39
  • 1
    Daniel's answer is the best solution IMO, but if changing the build file is not desirable then another option is to set `--env BP_GRADLE_BUILT_ARTIFACT=build/libs/[name of fat jar file].jar`. Using the Spring Boot Gradle plugin with `./gradle bootBuildImage` doesn't have this problem because the Spring Boot plugin has enough context to know that only the Boot fat jar should be sent to the Paketo builder. – Scott Frederick Dec 06 '22 at 17:37