quarkusio / quarkus-buildpacks

9 stars 3 forks source link

Question: Will paketo-buildpacks/java support the quarkus stacks ? #16

Open cmoulliard opened 2 years ago

cmoulliard commented 2 years ago

Question/Issue

Will the paketo-buildpacks/java builder support the quarkus stacks of this project or be adapted to support to build a quarkus app as OOTB the container fails to start ?

Steps to reproduce

If now, I build the quarkus app image using the image builder of this project, the container is well started and I can access the service localhost:8080

pack build quarkus_app -p ./ -B ghcr.io/halkyonio/quarkus-builder:jvm
jvm: Pulling from halkyonio/quarkus-builder
2a99c93da168: Already exists 
...
[exporter] Setting default process type 'web'
[exporter] Saving quarkus_app...
[exporter] *** Images (9442916d3cbd):
[exporter]       quarkus_app
[exporter] Adding cache layer 'io.quarkus.buildpacks.buildpack:m2repo'
Successfully built image quarkus_app

and

docker run -d -p 8080:8080 -e PORT=8080 quarkus_app                  
5cc6863a89302aa2d08c6ba8fa3425deb407b5fe0e945aa93eccb37b9dfb330a

docker ps
CONTAINER ID   IMAGE                  COMMAND                  CREATED         STATUS          PORTS                                                                                                                     NAMES
5cc6863a8930   quarkus_app            "/cnb/process/web"       5 seconds ago   Up 4 seconds    8443/tcp, 0.0.0.0:8080->8080/tcp, 8778/tcp                                                                                distracted_haibt

docker logs 5cc6863a8930
INFO exec  java -XX:+UseParallelGC -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=20 -XX:GCTimeRatio=4 -XX:AdaptiveSizePolicyWeight=90 -XX:+ExitOnOutOfMemoryError -cp ".:target/quarkus-app/lib" -jar /layers/io.quarkus.buildpacks.buildpack/1-app/quarkus-run.jar  
__  ____  __  _____   ___  __ ____  ______ 
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/ 
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \   
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/   
2022-02-10 08:09:38,449 INFO  [io.quarkus] (main) quarkus-petclinic 1.0.0-SNAPSHOT on JVM (powered by Quarkus 2.7.0.Final) started in 1.912s. Listening on: http://0.0.0.0:8080
2022-02-10 08:09:38,454 INFO  [io.quarkus] (main) Profile prod activated. 
2022-02-10 08:09:38,455 INFO  [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-orm, hibernate-orm-panache, jdbc-h2, kubernetes, micrometer, narayana-jta, qute, resteasy, resteasy-qute, smallrye-context-propagation, vertx]

FYI: @quintesse

dmikusa commented 2 years ago

I don't know what the custom builder you're using is doing, but the problem is that when you do a pack build, the Maven buildpack picks out the JAR to run and it's picking a JAR that's not executable. Thus no start command is set.

It matches target/*.jar by default.

dmikusa@dmikusa-a01 ~/C/S/q/getting-started (main)> ls target/*.jar
target/getting-started-1.0.0-SNAPSHOT.jar

dmikusa@dmikusa-a01 ~/C/S/q/getting-started (main)> unzip -p target/getting-started-1.0.0-SNAPSHOT.jar META-INF/MANIFEST.MF
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven 3.8.4
Built-By: dmikusa
Build-Jdk: 11.0.14

There's no Main-Class entry.

You need to set $BP_MAVEN_BUILT_ARTIFACT and point it to an executable JAR.

dmikusa commented 2 years ago

Hmm, it looks messier than that. I see ./target/quarkus-app/quarkus-run.jar which is executable, but it has class-path settings that depend on other files in the ./target/quarkus-app/lib directory.

You can make the Maven buildpack keep all of those files in /workspace, but you will have multiple files in /workspace and the paketo-buildpacks/executable-jar buildpack doesn't presently know how to find which one of the JAR files it should run. Is there a way to have Quarkus package up a fat JAR that contains all the dependency JAR files?


For what it's worth, we recently added support for Maven to persist multiple files into /workspace but only paketo-buildpacks/native-image has been updated to work with multiple files. This was primarily added for Quarkus and Native Image builds, which is a scenario that does presently work.

pack build getting-started -e BP_NATIVE_IMAGE=true -e BP_MAVEN_BUILD_ARGUMENTS="-Dquarkus.package.type=native-sources -Dmaven.test.skip=true package" -e BP_MAVEN_BUILT_ARTIFACT="target/native-sources" -e BP_NATIVE_IMAGE_BUILD_ARGUMENTS_FILE="native-sources/native-image.args" -e BP_NATIVE_IMAGE_BUILT_ARTIFACT="native-sources/getting-started-1.0.0-SNAPSHOT-runner.jar"

I'd like to add support for this but just haven't gotten to it yet. paketo-buildpacks/executable-jar needs some changes so it can find the right JAR.

matejvasek commented 2 years ago

@cmoulliard I recall it worked for me with uber-jar packaging, but I am not sure.

maxandersen commented 2 years ago

We really would prefer not having to use fat jar packaging as it comes with an overhead at runtime startup.

Any way to guide the build pack to that?

quintesse commented 2 years ago

I don't think this buildpack will ever be part of paketo, it would have to be rewritten from the ground up.

Right now any work to support Quarkus in paketo would have to be done upstream AFAIK. The simplest way would be for their basic Java buildpack to at least support Quarkus' packaging format (like ours/this one does). If we want better support it would have to be a Quarkus specific buildpack, just like they have one for Spring Boot. But I've looked at that one and it's not something simple, it seems like a serious amount of work.

In the last buildpack meeting in RH I think it was mentioned that there was already some intention in upstream to support Quarkus, but I don't know the status of that.

matejvasek commented 2 years ago

@maxandersen I think @dmikusa-pivotal is already looking into fix to support [fast|legacy].jar.

matejvasek commented 2 years ago

@quintesse just recently there was added support for Quarkus native build. I tried it on simple project and it worked. But one must specify many envvars by hand.

pack build test-bp --builder gcr.io/paketo-buildpacks/builder:base \
  -b paketo-buildpacks/graalvm -b paketo-buildpacks/java-native-image \
  --trust-builder=true --pull-policy=always -v \
  --env BP_MAVEN_BUILT_ARTIFACT="target/native-sources" \
  --env BP_NATIVE_IMAGE_BUILD_ARGUMENTS_FILE="native-sources/native-image.args" \
  --env BP_MAVEN_BUILD_ARGUMENTS="package -DskipTests=true -Dmaven.javadoc.skip=true -Dquarkus.package.type=native-sources" \
  --env BP_NATIVE_IMAGE=1 \
  --env BP_JVM_VERSION="11" \
  --env BP_NATIVE_IMAGE_BUILT_ARTIFACT="native-sources/function-1.0.0-SNAPSHOT-runner.jar" \
  --env BP_JVM_TYPE=JDK
quintesse commented 2 years ago

@matejvasek aha ok, thanks for the update!

Btw, AFAIK it was always possible to run Quarkus (non-native) anyway, as long as you were okay with building your app in certain ways (eg using uber jars as you mentioned). I was more looking towards something that would be able to run a Quarkus app as-is, without any changes necessary. It seems that wouldn't be too hard to add (the changes for jboss' run-java.sh weren't: https://github.com/quintesse/openjdk/commit/0864b463e79ddfe5b06b33386f9255a0d3923a82). But on the other hand perhaps upstream would see that as adding Quarkus-specific behaviour to an otherwise generic Java builder.

matejvasek commented 2 years ago

I was more looking towards something that would be able to run a Quarkus app as-is

Maybe there could be some slim Quarkus buildpack that would just prepare the envvars for the other participating buildpack (e.g. maven/native-image). But I don't know if that possible.

cmoulliard commented 2 years ago

I'd like to add support for this but just haven't gotten to it yet. paketo-buildpacks/executable-jar needs some changes so it can find the right JAR.

Is there a ticket opened to support such a feature ? @dmikusa-pivotal

cmoulliard commented 2 years ago

I tried it on simple project and it worked.

Is there a way to enable the native build stack instead of passing as parameter the stacks to be used -b .... to pack ? @matejvasek

matejvasek commented 2 years ago

Not yet. You need to pass right envvars so native-image BP knows what to compile. We might create some thin Quarkus BP that would populate those envvars automatically.

matejvasek commented 2 years ago

@quintesse what is best the way to determine what kind of build is used (fast,legacy,uber)?

matejvasek commented 2 years ago

also issue for non-native build https://github.com/paketo-buildpacks/executable-jar/issues/112 I'll try to fix it

cmoulliard commented 2 years ago

what kind of build is used (fast,legacy,uber)?

I think that we should expose using an ENV var the type of java archive we would like to have as it will impact how the run image will start.

quintesse commented 2 years ago

what is best the way to determine what kind of build is used (fast,legacy,uber)?

I'm not sure I understand correctly: "determine" by whom? Two options I see are: first, the builder could just set the required -D option to force it to use a specific kind of build. And secondly, if the first is not an option, because a generic builder is being used for example, then I think we can only look at the files being output. Just like I did for the Jboss script (https://github.com/quintesse/openjdk/commit/0864b463e79ddfe5b06b33386f9255a0d3923a82)

matejvasek commented 2 years ago

Two options I see are: first, the builder could just set the required -D option to force it to use a specific kind of build.

@quintesse Actually we might use this. Originally I meant if we can detect how was the app build just by looking at target content.

matejvasek commented 2 years ago

Determine might be incorrect word, what I meant is more like detect.

quintesse commented 2 years ago

what I meant is more like detect.

Sure, like I mentioned, you might detect it by looking at the target content as I did in the script I linked to. It's very easy and supports all 3 formats supported by Quarkus.

For generic builders the problem might indeed be that they assume that there is only a single artifact needed to run the code, while Quarkus, depending on the build type chosen, can use several (as was mentioned by @dmikusa-pivotal).

Now for paketo we could perhaps simple say that we only support the uber-jar format for simplicity's sake, but the fast-jar format is actually preferred if we want to show off Quarkus' best side. Btw, that format is not only preferred because it's faster but also because all dependencies are separate files, which means they can be put in a different layer which makes (re)building the code faster as well.

matejvasek commented 2 years ago

I'll try to write a prototype of Quarkus buildpack.

quintesse commented 2 years ago

@matejvasek for paketo you mean?

matejvasek commented 2 years ago

@quintesse yes paketo

rhuss commented 2 years ago

Out of curiosity, is there a buildpack with Quarkus support in Paketo ? Or what is currently the recommended way to build Quarkus apps with CNB ?

cmoulliard commented 2 years ago

Can you reply to Roland @BarDweller please ?

matejvasek commented 2 years ago

@rhuss as with s2i you just need to set some envvars.

  - name: BP_MAVEN_BUILT_ARTIFACT
    value: func.yaml target/quarkus-app/lib/ target/quarkus-app/*.jar target/quarkus-app/app/
      target/quarkus-app/quarkus/
  - name: BP_MAVEN_BUILD_ARGUMENTS
    value: package -DskipTests=true -Dmaven.javadoc.skip=true -Dquarkus.package.type=fast-jar
matejvasek commented 2 years ago

or use uber-jar (set it in application.properties)

matejvasek commented 2 years ago

I'll add bp for it in near future.

rhuss commented 2 years ago

Thanks @matejvasek, for the great workaround.

From a user's point of view it would be awesome though if a Quarkus build could be auto-detected as I suspect that Quarkus apps are not an uncommon use case and cnb is all about opinionated auto-detection, isn't it ?