Dhananjay.blog

Recipes for Java, Golang on Kubernetes and more.

Menu
  • Home
  • About
Menu

Container Image Reducing Size with Jib

Posted on September 15, 2022

In this post we will go over some best practices and easy steps to reduce container image size of your spring boot application built using Google Tool Jib.

We will be using the config-server SpringBoot application that was used in this post as a reference to perform image optimization. Please refer to the above post for the setup of this application and ensure you have built its docker image before proceeding with the next steps.

Review Container Image Layers

First lets check how big our image is and various layers within:

$ docker image ls
REPOSITORY    TAG       IMAGE ID       CREATED          SIZE
config-server 1.5       4bdc67d0880c   35 seconds ago   275MB

So thats our starting point, our image for the config-server is 275 MB, lets now inspect various layers within it. Run the following command where 4bdc67d0880c is the image id.

$ docker image history 4bdc67d0880c
Container Image layers

If you notice above the two biggest layers are the dependencies and the host OS or base image (highlighted in red). We will focus on reduce these in the remainder of the post.

Replace Base Container Image

A Base image has no Parent image specified in its Docker file and is created FROM scratch directive. There are two main projects which we can refer to:

Distroless Container Image

“Distroless” images contain only your application and its runtime dependencies. They do not contain package managers, shells or any other programs you would expect to find in a standard Linux distribution. Refer to the documentation for more details.

These images are generally leaner , but in our case both gcr.io/distroless/java11-debian11 (210MB) and gcr.io/distroless/java17-debian11 (231MB) are already too big to result in any concrete improvements.

Alpine Container Image

These images are based of Alpine Linux distribution which are designed to be small. Instead of using GNU Core utilties, gliblc and systemd alpine uses musl, BusyBox and OpenRC.

If your application can run well with java8, then openjdk:8-jre-alpine is just 84 MB!!. While java 11/17 versions are also worked for alpine, openjdk:8-jre-alpine might work for most workloads pretty well.

Lets replace the base image to this one in our build.gradle file add the following:

jib {
    from {
        image "openjdk:8-jre-alpine"
    }
}

Next, Rebuild the image using gradle jibDocker command, now lets see how much size reduction did we get

$ docker image ls
REPOSITORY      TAG    IMAGE ID          SIZE
config-server   1.5    a4f9feb22a11      139MB

So we reduced the size from 275 MB to 139 MB , thats more than 50% improvement just by replacing the base image.

Review Dependencies in Container Image

Next up, we will review the dependencies. The idea here is to review all dependencies and remove anything that is not used for our use case.

Container Image Layer

So we did reduce the base image layer, but we still have the dependency layer ~54 MB, so thats where we will focus next.

Lets print the dependency tree next and see if there is anything that we don’t want , run the following command within the root of the gradle project.

./gradlew -q dependencies --configuration runtimeClasspath
Dependency Map

You will get an output similar to the above screenshot. Review the dependencies carefully depending on your use case and start identifying anything that is not needed. For example in this case config-server already comes with logback, so we dont need anything related to log4j in there.

Exclude Unwanted Dependencies

Once the dependencies are identified the next step is to exclude them from the image, this can be done simply by adding the following to your gradle file, this removes this dependencies for all configurations.

configurations {
    all {
        exclude group: "org.apache.logging.log4j", module: "log4j-to-slf4j"
        exclude group: "org.apache.logging.log4j", module: "log4j-api"
    }
}

After image rebuild you will notice a slight difference in size , since log4j jar files are less than a MB. Using this approach your mileage might vary depending on how optimized your dependencies already are.

There are multiple ways to exclude dependencies which gives you more control over what is being removed. Refer to the Gradle documentation for more details.

More Considerations

  • Reduce no of Layers within the image.
  • Don’t embed application data or configuration within the image.
  • Reduce Dependencies by using components from the smaller no of libraries to reduce size.

Further Reading

  • Google Gradle Jib Tool
  • Docker Storage Drive and Image Layers
  • Google Tool JIb

Categories

  • GO
  • Home
  • Java
  • K8s and More
  • Programming
  • Software

Tags

Container Image Docker gingonic go helm jib kafka kubernetes microservices springboot spring cloud config tdd test driven development unit testing

Recent Posts

  • Unit Testing Checklist
  • ConfigMap Custom Watcher with SpringBoot
  • Go Service Configuration with k8s ConfigMaps
  • Go MicroService in Gin using Helm On k8s
  • Container Image Reducing Size with Jib

Archives

  • March 2025
  • January 2023
  • December 2022
  • September 2022
  • August 2022

Categories

  • GO
  • Home
  • Java
  • K8s and More
  • Programming
  • Software

About

  • Privacy
  • Terms of Service
  • About
  • Contact
@2024 Dhananajay on Tech