I tried to use Jib Maven with Quarkus and it turned out not working at all.
Basically, Jib can't find the Main class and can't copy the dependency libs because all of them are provided scope.
quarkus-resteasy and quarkus-arc dependencies to provided; making them compile then causes quarkus:build to failquarkus:build looks to be doing some class changes (_augmentation_) and class generation, including generating a main class (io.quarkus.runner.GeneratedMain) which is in target/wiring-classes.I suspect the only feasible solution here is to do the full package to create an image around the runnable jar (#530).
Or better yet, quarkus could use Jib-Core internally to package their container image!
Would be good to be able to also build the docker images for the native-image part of quarkus.
I know this is maybe not in the scope of Jib (java application only), but I think this could be good!
Hi,
quarkus could use Jib-Core internally to package their container image!
Quarkus itself isn't building any container images, it relies on external tools (Docker, podman) for doing so. It provides ready-to-use Dockerfiles, though.
Taking a step back, here is what Quarkus produces:
io.quarkus.runner.GeneratedMain) and a _META-INF/MANIFEST.MF_ referring to that class and setting up the classpathI tried using containerizingMode=packaged, but still am getting the error about the main class not being found. I suppose #1470 is needed for that.
Interesting. We need to look this into further. @gunnarmorling you can set <container><mainClass>com.example.SomeClass. Should work with <containerizingMode>packaged.
Thanks! Doing that, I can indeed build an image now, but it'll fail upon start-up, with the main class not being found. So it seems aforementioned runner JAR isn't added to the image.
Ah, yeah, Jib will probably use target/my-app-1.0.0-SNAPSHOT.jar instead of target/my-app-1.0.0-SNAPSHOT-runner.jar. Can you rename my-app-1.0.0-SNAPSHOT-runner.jar to my-app-1.0.0-SNAPSHOT.jar and run Jib (don't do mvn clean) to see if it works?
And do you define any special classifier (the -runner part) for any plugins you use in your pom.xml?
if quarkus is setting the mavenProject artifact (https://maven.apache.org/ref/3.2.3/apidocs/org/apache/maven/project/MavenProject.html#setArtifact(org.apache.maven.artifact.Artifact)) then we might need to ensure the quarkus goal is executed before jib tries to access the artifact.
Can you rename my-app-1.0.0-SNAPSHOT-runner.jar to my-app-1.0.0-SNAPSHOT.jar and run Jib (don't do mvn clean) to see if it works?
Yes, that works!
then we might need to ensure the quarkus goal is executed before jib tries to access the artifact.
I don't think the runner JAR is actually set as the artifact, as mvn package jib:dockerBuild fails (which does run the Quarkus Maven plug-in before Jib). I reckon that the plug-in just creates the runner JAR "out of bands".
Can you rename my-app-1.0.0-SNAPSHOT-runner.jar to my-app-1.0.0-SNAPSHOT.jar and run Jib (don't do mvn clean) to see if it works?
Yes, that works!
Thanks for the update. And I assume there's nothing explicitly mentioning the runner classifier in your pom.xml. If so, I guess the Quarkus Maven plugin just automatically appends the -runner suffix. In any case, this was just to verify how the Quarkus plugin works. Most likely this trick shouldn't be used. I fear my-app-1.0.0-SNAPSHOT-runner.jar may be a fat JAR embedding all dependency JARs. In that case, you will essentially duplicate dependency JARs in the container image. Even before that, it is very inefficient to put a fat JAR, which Jib is trying to avoid as much as possible. But if it is not a fat JAR, it's probably fine to use the -runner JAR.
We certainly need to dig into Quarkus. We'll do it soon.
No, the runner JAR is not a fat JAR. All the dependencies are copied by Quarkus into _target/lib_. So a Dockerfile build will run these commands typically for a Quarkus app:
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/app.jar
nothing explicitly mentioning the runner classifier in your pom.xml
Yes, exactly.
Awesome. Then, simply making Jib pick up my-app-1.0.0-SNAPSHOT-runner.jar instead of the original JAR could be a sane and simple solution, although I'll have to experiment a bit to check. Although Jib won't look into target/lib, it will copy all the dependencies defined in Maven into /app/libs/* in the image. So it may just work.
So the nice thing about quarkus is that it follows the java model of specifying the classpath in the MANIFEST.MF, which allows us to run java -jar quarkus-app.jar if the dependencies are the right place.
It seems like if we know the user's jar contains manifest entries for deps/mainclass then we should just use that metadata to build the container in packaged mode? (like: https://github.com/GoogleCloudPlatform/appengine-plugins-core/blob/master/src/main/java/com/google/cloud/tools/appengine/operations/AppYamlProjectStaging.java#L216)
Ofcourse this would require us to rethink completely how we do "packaged"
One thing I'm just realizing: is there a way to make Jib copy the libraries from _target/lib_ instead of the original project dependencies as derived from the POM? Quarkus may do some transformations of classes, in which case taking the original ones wouldn't work.
If it's of interest, I've pushed a minimal example of what I currently have to a repo here. I think the dependency issue outlined before is a problem, though.
@gunnarmorling thanks for sharing the repo. Apparently Quarkus unpacks dependency JARs, does some magic class transformation inside them, re-packages, and places them under target/lib? To support this scenario, we certainly need something extra in Jib. This is related to implementing a general support for a fat/uber JAR and java -jar, so I need to examine this further.
And I see in your sample repo that one of your next steps is "enable usage of classes directory without the need to build a runner JAR". Is it currently possible to run a Quarkus app without using a runner JAR? That is, just with java -cp <some classpath> some.main.Class if using right classpath without a runner JAR?
This is related to implementing a general support for a fat/uber JAR and
java -jar, so I need to examine this further.
What is the status of this request @chanseokoh ?
I'll add my experience as part of the team of people involved with Quarkus:
@gunnarmorling thanks for sharing the repo. Apparently Quarkus unpacks dependency JARs, does some magic class transformation inside them, re-packages, and places them under
target/lib? To support this scenario, we certainly need something extra in Jib. This is related to implementing a general support for a fat/uber JAR andjava -jar, so I need to examine this further.
Yes, this description is (mostly) correct. The end result of mvn package with the Quarkus Maven plugin bound to the package phase (and the native-binary support not enabled) is the creation of target/lib (containing the dependencies - potentially transformed meaning that these are the dependencies that must be used when running the produced jar) and the *-runner.jar (which contains the compiled user code and the Quarkus generated classes). This is the default mode - if one uses -Dquarkus.package.uber-jar=true then an uber-jar is created containing all the code and dependencies.
And I see in your sample repo that one of your next steps is "enable usage of classes directory without the need to build a runner JAR". Is it currently possible to run a Quarkus app without using a runner JAR? That is, just with
java -cp <some classpath> some.main.Classif using right classpath without a runner JAR?
The Main Class is generated by Quarkus and is always named io.quarkus.runner.GeneratedMain. However there is currently no "packaging" option that doesn't create the runner jar.
Also it's worth mentioning that both the dependencies in lib and the generated main class are part of the META-INF/MANIFEST.INF metadata (inside the *-runner.jar)
@cmoulliard initially we had considered adding special support for Quarkus inside Jib, which might have been not so difficult to add in a short time frame. However, as we explored other closely related issues as well as other various issues, we've conceived something very general at a grand scale that can cover a wide spectrum of use cases including Quarkus. This new idea requires a lot of rearchitecturing of Jib codebase, so unfortunately this will take quite some time to be materialized.
@geoand thanks for explaining and confirming. This helps a lot. If you need any help in the meantime, let us know.
@chanseokoh Will do :)
Support for Quarkus has been added on the Quarkus side. See https://quarkus.io/guides/container-image#jib
Hi @geoand ,
Could you please provide an example of using the jib extension for Quarkus?
I added the extension to my Quarkus app and also added following to application.properties
quarkus.container-image.build=true
After running
./mvnw clean package -e
I get following error:
[ERROR] Failed to execute goal io.quarkus:quarkus-maven-plugin:1.3.1.Final:build (default) on project eprescribe: Failed to build quarkus application: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[ERROR] [error]: Build step io.quarkus.container.image.jib.deployment.JibProcessor#buildFromJar threw an exception: java.lang.IllegalArgumentException
[ERROR] at com.google.common.base.Preconditions.checkArgument(Preconditions.java:127)
[ERROR] at com.google.cloud.tools.jib.api.ImageReference.of(ImageReference.java:166)
[ERROR] at io.quarkus.container.image.jib.deployment.JibProcessor.getImageReference(JibProcessor.java:178)
[ERROR] at io.quarkus.container.image.jib.deployment.JibProcessor.createContainerizer(JibProcessor.java:135)
[ERROR] at io.quarkus.container.image.jib.deployment.JibProcessor.containerize(JibProcessor.java:118)
[ERROR] at io.quarkus.container.image.jib.deployment.JibProcessor.buildFromJar(JibProcessor.java:77)
.......................................
Caused by: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
[error]: Build step io.quarkus.container.image.jib.deployment.JibProcessor#buildFromJar threw an exception: java.lang.IllegalArgumentException
at com.google.common.base.Preconditions.checkArgument(Preconditions.java:127)
at com.google.cloud.tools.jib.api.ImageReference.of(ImageReference.java:166)
at io.quarkus.container.image.jib.deployment.JibProcessor.getImageReference(JibProcessor.java:178)
at io.quarkus.container.image.jib.deployment.JibProcessor.createContainerizer(JibProcessor.java:135)
at io.quarkus.container.image.jib.deployment.JibProcessor.containerize(JibProcessor.java:118)
at io.quarkus.container.image.jib.deployment.JibProcessor.buildFromJar(JibProcessor.java:77)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
Regards,
Giriraj
@gbhojak https://quarkus.io/guides/container-image has the documentation. But if you are still facing issues, please join the Quarkus chat so we can try and help.
@gbhojak @geoand
[ERROR] at com.google.common.base.Preconditions.checkArgument(Preconditions.java:127)
[ERROR] at com.google.cloud.tools.jib.api.ImageReference.of(ImageReference.java:166)
This check tells that an image reference string (particularly the repository portion) is not in a valid format. For example, using a character not allowed in an image reference. Not sure if it is the user of the Qaurkus plugin providing an invalid string, but someone should double-check if the image reference syntax is correct. A typical example would be
registry portion | repository portion |
--------------------+---------------------+------
my.registry.com:port/my/awesome/repository:my-tag
See the following links for more details.
https://docs.docker.com/engine/reference/commandline/tag/#extended-description
https://github.com/docker/distribution/blob/master/reference/reference.go
Quarkus shouldn't on its own provide a malformed image name.
But it could happen depending on the settings the user supplied.
We should definitely improve the error message at least. I'll do it soon
@geoand and @chanseokoh , the issue building the image locally was due to presence of invalid characters in following properties:
quarkus.container-image.group=quarkus
quarkus.container-image.name=demo-app
quarkus.container-image.tag=1.0
After using the right value for these properties(as above), there wasn't any error.
Thank you for your prompt help with the issue.
@gbhojak Thanks for checking.
I'm going to improve the error message in Quarkus to provide users with some pointers on what might be wrong.
@gunnarmorling @geoand @maxandersen @cmoulliard @OneCricketeer @sureshg @dgageot @saturnism
@daggerok @sirAlexander @ScheerMT @dennisjagut @Tanmayshetty @krishnaarava @Tombar @jycr @DaHoC @yazidaqel @sdavids @xmlking @jabrena @mehmandarov @YacheLee
Although Quarkus added native Jib image building on their side a while ago, we still wanted to allow Jib build plugin users to containerize Quarkus apps. However, as mentioned above, we thought adding specialized code for every app framework and non-conventional feature requests into Jib plugins is not sustainable or maintainable in the long run. For this reason, we implemented the Jib extension framework which gives the user the power to tweak and extend Jib plugin workings.
With the new extension framework, now we enabled Quarkus support in Jib plugins through the release of Jib Quarkus Extensions (Maven / Gradle). Currently, the extensions only work for the default packaging mode (e.g., no support for uber-jar package type), but we should be able to add more support in the extensions in the future. Another point of supporting Quarkus through an extension is to attract more contributions from interested parties and the community, so we are more than welcome to have your contributions.
Would be good to be able to also build the docker images for the
native-imagepart of quarkus.
I know this is maybe not in the scope of Jib (java application only), but I think this could be good!
@davinkevin ultimately, our Jib Quarkus Extensions can be expanded to cover the native-image package type. Related, we will soon write another Jib extension to support a general native GraalVM (i.e., non-Quarkus) containerization.
Closing the issue.
Awesome news!
One note: I wouldnt expect jib native-image would be recommended to quarkus users as there are settings/flags necessary that works well specifically with quarkus style apps - thus i wouldassume when jib is invoked the native binary would already be available.
Most helpful comment
@gunnarmorling @geoand @maxandersen @cmoulliard @OneCricketeer @sureshg @dgageot @saturnism
@daggerok @sirAlexander @ScheerMT @dennisjagut @Tanmayshetty @krishnaarava @Tombar @jycr @DaHoC @yazidaqel @sdavids @xmlking @jabrena @mehmandarov @YacheLee
Although Quarkus added native Jib image building on their side a while ago, we still wanted to allow Jib build plugin users to containerize Quarkus apps. However, as mentioned above, we thought adding specialized code for every app framework and non-conventional feature requests into Jib plugins is not sustainable or maintainable in the long run. For this reason, we implemented the Jib extension framework which gives the user the power to tweak and extend Jib plugin workings.
With the new extension framework, now we enabled Quarkus support in Jib plugins through the release of Jib Quarkus Extensions (Maven / Gradle). Currently, the extensions only work for the default packaging mode (e.g., no support for uber-jar package type), but we should be able to add more support in the extensions in the future. Another point of supporting Quarkus through an extension is to attract more contributions from interested parties and the community, so we are more than welcome to have your contributions.
@davinkevin ultimately, our Jib Quarkus Extensions can be expanded to cover the
native-imagepackage type. Related, we will soon write another Jib extension to support a general native GraalVM (i.e., non-Quarkus) containerization.Closing the issue.