eclipse-jkube / jkube

Build and Deploy java applications on Kubernetes
https://www.eclipse.dev/jkube/
Eclipse Public License 2.0
775 stars 521 forks source link

JIB build breaks for spring-boot if classifier is used #1292

Open michael-mader opened 2 years ago

michael-mader commented 2 years ago

Description

I am building an image with jib for a spring-boot application. Spring-boot applications need to be repackaged in a fat jar so that you can run java -jar myApp.jar.

This repackaging can either happen in place or with a classifier. A classifier exec leads to two jars:

Where myApp-exec.jar is the fat jar.

kubernetes-maven-plugin seems to be able to find correct (fat) jar file but only if run in zero config mode. In this demo repository (a fork of spring-boot-with-jib example from jkube repo) https://github.com/michael-mader/jkube/tree/master/quickstarts/maven/spring-boot-with-jib I have added the repackaging with a classifier.

There are two profiles Jib-Zero-Config and Jib-With-Assembly. Running with the zero config profile selects the correct fat jar and puts it into the container. Running the other profile with some configuration causes the other jar to be included in the container. This jar cannot be run as it is missing the main manifest attribute.

Info

* Kubernetes / Red Hat OpenShift setup and version : -

* If it's a bug, how to reproduce: 

works as expected

mvn clean package k8s:build -PJib-Zero-Config

does add the wrong jar

mvn clean package k8s:build -PJib-With-Assembly



* Sample Reproducer Project : https://github.com/michael-mader/jkube/tree/master/quickstarts/maven/spring-boot-with-jib
rohanKanojia commented 2 years ago

Does it work when you modify your image configuration to copy the classifier jar also?

When using XML configuration, we should ideally be providing everything via configuration. Looks like this behavior is caused by JKubeProjectUtil.getFinalOutputArtifact copying jar automatically into image. Zero configuration uses FatJarDetector which seems to select correct jar.

        <profile>
            <id>Jib-With-Assembly</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.eclipse.jkube</groupId>
                        <artifactId>kubernetes-maven-plugin</artifactId>
                        <version>${jkube.version}</version>
                        <configuration>
                            <images>
                                <image>
                                    <name>rohankanojia/spring-boot-sample</name>
                                    <build>
                                        <from>fabric8/java-centos-openjdk8-jdk:1.5.6</from>
                                        <assembly>
                                            <inline>
                                                <id>copy-test-file</id>
                                                <files>
                                                    <file>
                                                        <source>
                                                            ${project.basedir}/static/testFile.txt
                                                        </source>
                                                        <outputDirectory>static</outputDirectory>
                                                    </file>
                                                    <file>
                                                        <source>
                                                            ${project.basedir}/target/${project.artifactId}-${project.version}-exec.jar
                                                        </source>
                                                        <outputDirectory>deployments</outputDirectory>
                                                    </file>
                                                </files>
                                            </inline>
                                            <targetDir>/deployments</targetDir>
                                        </assembly>
                                        <cmd>java -jar /deployments/${project.artifactId}-${project.version}-exec.jar</cmd>
                                        <ports>
                                          <port>8080</port>
                                        </ports>
                                    </build>
                                </image>
                            </images>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>
manusa commented 2 years ago

With a manual assembly configuration, you are responsible of including the files that you want.

Looks like this behavior is caused by JKubeProjectUtil.getFinalOutputArtifact

By the default, the assembly will include what Maven has set as the main artifact for the project.

In you current scenario, you don't want that file, so in addition to what Rohan pointed out, you should also add the <excludeFinalOutputArtifact>true</excludeFinalOutputArtifact> option to your <assembly> configuration.

michael-mader commented 2 years ago

Does it work when you modify your image configuration to copy the classifier jar also?

When using XML configuration, we should ideally be providing everything via configuration. Looks like this behavior is caused by JKubeProjectUtil.getFinalOutputArtifact copying jar automatically into image. Zero configuration uses FatJarDetector which seems to select correct jar.

        <profile>
            <id>Jib-With-Assembly</id>
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.eclipse.jkube</groupId>
                        <artifactId>kubernetes-maven-plugin</artifactId>
                        <version>${jkube.version}</version>
                        <configuration>
                            <images>
                                <image>
                                    <name>rohankanojia/spring-boot-sample</name>
                                    <build>
                                        <from>fabric8/java-centos-openjdk8-jdk:1.5.6</from>
                                        <assembly>
                                            <inline>
                                                <id>copy-test-file</id>
                                                <files>
                                                    <file>
                                                        <source>
                                                            ${project.basedir}/static/testFile.txt
                                                        </source>
                                                        <outputDirectory>static</outputDirectory>
                                                    </file>
                                                    <file>
                                                        <source>
                                                            ${project.basedir}/target/${project.artifactId}-${project.version}-exec.jar
                                                        </source>
                                                        <outputDirectory>deployments</outputDirectory>
                                                    </file>
                                                </files>
                                            </inline>
                                            <targetDir>/deployments</targetDir>
                                        </assembly>
                                        <cmd>java -jar /deployments/${project.artifactId}-${project.version}-exec.jar</cmd>
                                        <ports>
                                          <port>8080</port>
                                        </ports>
                                    </build>
                                </image>
                            </images>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </profile>

ok thanks for your answer. I'll check if it is working like you suggested. But I still don't understand, why the spring-boot generator is not used in this scenario? My understanding was, that you can add explicit configuration on top, but it seems like you are replacing everything when setting a configuration.

Edit: Thank you! It is working with your and @manusa proposed changes. @manusa This seems to be not (only) caused by <assembly> as I did not have any assembly Tags in my project before. Setting <configuration> seems to be enough for the default mechanisms to "fail"

manusa commented 2 years ago

Generators are meant to provide an opinionated image configuration for your project. They are a zero-config alternative to <configuration><images><image>.

The fact that you provide an image configuration for your project, in most cases will disable the zero-config generators.

seems to be enough for the default mechanisms to "fail"

This shouldn't be the case. However, setting <configuration><images><image> in most cases does (due to the mentioned reasons).

My understanding was, that you can add explicit configuration on top, but it seems like you are replacing everything when setting a configuration

You can add configuration on top, but configuration which is not mutually exclusive such as a manually configured image.

e.g. for the Spring Boot generator you can set most of the java-exec options, plus color customization.

I see this confusion on many users, but we can't really find a proper way to explain this better.

In a nutshell, JKube provides three ways to generate Container Images:

michael-mader commented 2 years ago

thanks for making this clear!