2

I have a multi-modules project from which I build spring boot apps using Jib. I understood that fat JAR into container prevents building image efficiently (see) but one particular module needs to be packaged into a fat JAR file. As I would like to keep the same building tool for the whole multi-modules project, is it possible to package fat jar using Jib?

I already tried the repackage goal

<plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.3.5.RELEASE</version>
    <executions>
        <execution>
            <goals>
                <goal>repackage</goal>
            </goals>
        </execution>
    </executions>
</plugin>

that is packaging the app such as

app
├── classpath
│   └── import-metadata-service-0.0.1-SNAPSHOT.original.jar
└── libs
    ├── HdrHistogram-2.1.12.jar
    ├── LatencyUtils-2.0.3.jar
    ├── apache-jena-libs-3.13.0.pom 
    ...
AriesNinja
  • 55
  • 10
charlycou
  • 1,778
  • 13
  • 37
  • There is a hacky way to achieve what you want. But before that, we'd like to understand if if you are seeing a different app behavior in any way between the ordinary thin JAR containerization (as indicated by `.original.jar` in the image) and a Spring Boot fat JAR? If so, could you file an issue on the Jib repo? What's the issue that you can't take the original thin JAR? – Chanseok Oh Nov 16 '20 at 16:15
  • The fatjar also needs to be copied to another image. Keeping this packaging I would not have to change the image in which the fatjat is copied to. I'm not thinking of opening an issue for my very specific use case since its not the scope of jib at all. I'm thinking of using another build tool because even if I can manage to package the app as a fatjar the hacky way I would certainly have to modify the other image since I wouldn't be able to use `java -jar` directly ([ref](https://github.com/GoogleContainerTools/jib/blob/master/docs/faq.md#i-want-to-containerize-a-jar)), isn't it? – charlycou Nov 16 '20 at 19:18
  • 1
    Alright, I'll not question why you want this. There are a couple different creative (hacky) ways to achieve this, but maybe the simplest one is to copy your fat JAR using the `` feature to wherever you want, set `` to do `java -jar ...` (whatever command you want), and [remove the entire `/app/*`](https://gitter.im/google/jib?at=5fad68c5d37a1a13d6a12174) using the [Jib Layer-Filter extension](https://github.com/GoogleContainerTools/jib-extensions/tree/master/first-party/jib-layer-filter-extension-maven). – Chanseok Oh Nov 16 '20 at 20:26
  • 1
    FYI, we are currently working on releasing a CLI tool called "Jib CLI", and Jib CLI would probably be a better fit for the workflows like yours. Stay tuned. – Chanseok Oh Nov 16 '20 at 20:28

2 Answers2

3

Yes, it is possible to put a fat jar on to the container image using Jib. Please use "containerizingMode" configuration option of Jib:

<plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>build</goal>
            </goals>
        </execution>
   </executions>
    <configuration>
        <containerizingMode>packaged<containerizingMode>                
    </configuration>
</plugin>

Please refer https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#extended-usage for a full set of Jib configuration option.

Sanjeev Sachdev
  • 1,241
  • 1
  • 15
  • 23
  • I'm not sure the dependencies are packaged in the JAR file with this option. I need to verify but I remember testing that. Also I'm pretty confident @ChanseokOh would have given me this answer if you could do it this way. I can see he is contributing a lot to Jib github. I'll let you know – charlycou Jan 13 '21 at 19:29
  • Dependencies are definitely packaged in the JAR file. You may verify this by extracting the JAR output of the build -- you will find them under BOOT-INF/lib. Do let me know if you found them. – Sanjeev Sachdev Jan 14 '21 at 03:30
  • Dependencies defined as scope provided are not added as it is in Spring Boot fat-jar – Dawid Świtoń-Maniakowski Oct 13 '22 at 11:59
1

In case someone is stumbling over this: I have a similar usecase where I want to take advantage of jib (Dockerfile-less + can be used without docker daemon), but I currently cannot turn away from fat jars for other reasons.

Based on Chanseok comments (under the question), I came up with following, which will:

  • drop any layers added by jib
  • add the fatjar (by default in target/${build.finalName}.jar) into its own layer
  • overwrite entrypoint to execute "java -jar ..." instead of regular entrypoint pointing to your Main
  • Jib is called explicitly and not bound to lifecycle (at least in my sample), so it would have to be called explicitly with following mvn package jib:dockerBuild (or ... jib:build for a docker-daemon-less build)
  • using dive, you see that only one layer was added and that it is fairly large (== fat jar) inspection with dive

Sources: https://gitter.im/google/jib?at=5fad68c5d37a1a13d6a12174 + https://github.com/GoogleContainerTools/jib/tree/master/jib-maven-plugin#extradirectories-object

That sample works at least with spring boot 2.4.X

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
        <plugin>
            <groupId>com.google.cloud.tools</groupId>
            <artifactId>jib-maven-plugin</artifactId>
            <version>3.0.0</version>
            <dependencies>
                <dependency>
                    <groupId>com.google.cloud.tools</groupId>
                    <artifactId>jib-layer-filter-extension-maven</artifactId>
                    <version>0.2.0</version>
                </dependency>
            </dependencies>
            <configuration>
                <container>
                    <entrypoint>java,-jar,/app/${project.build.finalName}.jar</entrypoint>
                </container>
                <extraDirectories>
                    <paths>
                        <path>
                            <from>target/</from>
                            <includes>*.jar</includes>
                            <into>/app</into>
                        </path>
                    </paths>
                </extraDirectories>
                <pluginExtensions>
                    <pluginExtension>
                        <implementation>com.google.cloud.tools.jib.maven.extension.layerfilter.JibLayerFilterExtension</implementation>
                        <configuration implementation="com.google.cloud.tools.jib.maven.extension.layerfilter.Configuration">
                            <filters>
                                <filter>
                                    <!-- exclude all jib layers, which is basically anything in /app -->
                                    <glob>/app/**</glob>
                                </filter>
                                <filter>
                                    <!-- this is our fat jar, this should be kept by adding it into its own layer -->
                                    <glob>/app/${project.build.finalName}.jar</glob>
                                    <toLayer>jib-custom-fatJar</toLayer>
                                </filter>
                            </filters>
                        </configuration>
                    </pluginExtension>
                </pluginExtensions>
            </configuration>
        </plugin>
    </plugins>
</build>
DRoppelt
  • 406
  • 1
  • 4
  • 14