spring-bootkotlingraalvmpaketo

Paketo Spring boot 3.0 jar issue


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!


Solution

  • 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.