java/spring-boot/gradle Wrong Entrypoint in image built with pack and paketobuildpacks/builder:base - gradle

I have a really simple java spring-boot gradle application.
When I build an image from source with:
pack build testapp:0.0.1 --builder paketobuildpacks/builder:base
and try to run it with docker I get the following error:
ERROR: failed to launch: determine start command: when there is no default process a command is required.
The generated Entrypoint in this image is "/cnb/lifecycle/launcher".
When I inspect the image with pack inspect-image there are no processes.
I tried this with different java spring-boot gradle applications. When I use the "bootBuildImage" gradle task, it does nearly the same but uses the pre-build .jar-file and the resulting image works. The generated Entrypoint in this image is "/cnb/process/web" and pack inspect-image shows three processes.
Any ideas?

I can't see your build output, but it sounds like you're hitting a known issue. If this is not your problem, please include the full output of running pack build.
Onto the issue. By default, Spring Boot Gradle projects will build both an executable and non-executable JAR. Because this produces two JAR files, it presently confuses the buildpacks.
There are a couple of solutions:
Tell Gradle to not build the non-executable JAR. The buildpack requires the executable JAR. You can do this by adding the following to your build.gradle file:
jar {
enabled = false
}
This is the solution we have used in the Paketo buildpack samples.
If you don't want to make the change suggested in #1, then you can add the following argument to pack build: -e BP_GRADLE_BUILT_ARTIFACT=build/libs/<your-jar>.jar. For ex: -e BP_GRADLE_BUILT_ARTIFACT=build/libs/demo-0.0.1-SNAPSHOT.jar. You can use glob-style pattern matching here, but you need to make sure that what you enter does not match *-plain.jar. That will be the non-executable JAR that gets built by default.
This option just simply tells the Gradle buildpack more specifically what the JAR file to pass along to subsequent buildpacks.
We also have an open issue that should help to mitigate this problem. When the executable-jar buildpack gains support for multiple JARs, it'll be less likely that you'll need to set this. Essentially, this fill will add support so the executable-jar buildpack can inspect and detect an executable JAR, which would allow it to throw out the -plain.jar file since it's not executable.

Related

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

How to solve the problem with docker run while running image of Spring Boot App

I am new at Docker and trying to build and run my own container with Spring Boot Application. It runs on Kotlin and Gradle.
I have built the image with simply this command, provided by gradle with spring boot plugin (id("org.springframework.boot") version "2.7.0-SNAPSHOT")
gradlew bootBuildImage
As a result i am getting this. Here are the logs: https://pastebin.com/xMW82vcw
The problem is, while trying to run my built image i am getting this error.
C:\projects\monetka-app>docker run docker.io/library/monetka-app:0.0.1-SNAPSHOT
Setting Active Processor Count to 6
unable to determine class count
unable to walk /workspace
unable to open ZIP /workspace/META-INF/licenses/client-2.1.jar
read /workspace/META-INF/licenses/client-2.1.jar: is a directory
ERROR: failed to launch: exec.d: failed to execute exec.d file at path '/layers/paketo-buildpacks_bellsoft-liberica/helper/exec.d/memory-calculator': exit status 1
Here are the docker images i have locally
in docker desktop.
My gradle version is 7.4.1, and JDK in use is 17.
When you run gradlew bootBuildImage, you're using Cloud-Native buildpacks to generate the image. This is a bug in a tool installed by the buildpack.
The Java Cloud-Native buildpack will install a tool called memory-calculator. This tool runs prior to your application starting up and sets up all the JVM memory flags that are required to keep the JVM from going past the defined memory limit you set. For example, if you set the memory limit of your container to be 1G, the memory calculator will adjust settings like -Xmx accordingly.
To do this, the memory calculator needs to know how many class files you have in your application, so it searches for them. This process is failing because it sees something with an extension of .jar and so it's trying to read the number of class files in that JAR, however, what it's seeing META-INF/licenses/client-2.1.jar isn't actually a JAR. It's a directory.
I opened a bug report for you here: https://github.com/paketo-buildpacks/libjvm/issues/160
If you are able to remove the file META-INF/licenses/client-2.1.jar (or change so it doesn't have a .jar extension) you should be able to work around this until we can resolve the issue.

Error: Could not find or load main class com.networknt.server.Server error

I have a quick question. Do you have a light-4j framework docker image hosted somewhere in which I can just add my API jar and run docker? I am getting a hard time running my APIs generated using codegen CLI in docker. It consistently gives me Error: Could not find or load main class com.networknt.server.Server error
Have you tried mvn clean install exec:exec? If you want to run with the jar file, you need to build with mvn clean install -Prelease to generate the final fat jar.
This is one of the features contributed by one of the members to speed up the testing cycle to avoid building all extra artifacts for each cycle. It might confuse new developers, though. The generated README.md has some information on how to build and start. Let me know it is not clear, and I will add extra info. When you run the build.sh to generate a docker image, it will be built with -Prelease in the script.

Makefile to gradle conversion for golang application

I have a go lang application which exposes a rest API and logs the information to DB. I am trying to convert the make file to gradle build. Is there any default way similar to maven2gradle plugin or the gradle build file should be written manually? I checked the syntactical differences between gradle and make file but still not clear about passing run time arguments to gradle that is similar to
run:build
./hello -conf=/apps/content/properties/prop.json -v=0 -logDest="FILE" -log_dir="/var/log/logdir"
hello is my executable and others are the runtime arguments. This is my first attempt in migrating make to gradle and I couldnt find any clear documentation. Please help.
As far as I have checked, there is no direct plugin that could do this task. As a workaround, the build execution could be written as seperate tasks in gradle and ordered accordingly. Tasks here would contain setting Go path, installing dependencies and building the application and would be run as command line process in Gradle. Gradle provides support to run command line processes as described in gradle documentation. Hope it helps.

problems running state machine examples

Congratulations on the spring state machine, I found it yesterday and have been trying it out, specifically the turnstile example running in STS. I found it very easy and intuitive to build a FSM.
Because spring shell doesn't work well in STS I tracked down the instructions to run the examples from the command line in the reference doc,
"java -jar
spring-statemachine-samples-turnstile-1.0.0.BUILD-SNAPSHOT.jar"
,
but running it got an error
"no main manifest attribute, in spring-statemachine-samples-turnstile-1.0.0.BUILD-SNAPSHOT.jar".
Although not even a novice in using gradle, I tried fixing this by adding this line to build.gradle in the jar section
"manifest.attributes['Main-Class'] = 'demo.turnstile.Application'"
(which doesn't handle the various sub-projects I know) but got this error
"NoClassDefFoundError: org/springframework/shell/Bootstrap".
If it is possible to run the samples from gradle, could you include them in the reference document? I tried running the samples using
gradle run
but it there was no interaction with the shell scripts.
Samples are designed to be run as executable jar and with shell so that you can interact without a need to recompile with every change. Your error indicates that you didn't build that sample jar as mentioned in docs.
./gradlew clean build -x test
This will automatically use spring boot plugin which will add the necessary jar manifest headers to jar meta info to make it a true executable jar. Essentially every every sample is a spring boot app.
Building SM sample projects in Windows Environment:
Open Command prompt (windows key + r -->cmd-->Enter), Change directory to project root folder spring-statemachine-master (Inside the Extracted folder).
Run gradlew install to get all spring dependencies copied to local machine.
Run gradlew clean build -x test to get the spring shell jars built. Courtesy Janne
These steps should ideally get all .jar built, look into \build\libs folder of respective sample project for jar files.
Run the like any other java jar file java -jar [jar-file-name.jar] (make sure to be change directory to jar file directory location).
One more thing where I was stuck was, How to give events to SM:
It's like this sm event EVENT_NAME_AS_DEFINED_IN_CLASS. Ref
E.g.: sm event RINSE --> to washer project

Resources