Build Containers with Jib: Simplify Containerization Workflow

Rajesh Vinayagam
9 min readJun 6, 2023

Containerization has become a standard practice for deploying and running applications, and Java applications are no exception. Traditionally, building containers involved writing Dockerfiles and managing complex configurations. However, with the introduction of Jib, a containerization tool by Google, the process has become much simpler and more efficient. In this article, we will explore how to build containers for Java applications using Jib, highlighting its benefits and providing step-by-step instructions.

What is Jib, and why should you use it?

Jib is a containerization tool developed by Google that simplifies the process of building and deploying Java applications into containers. It is specifically designed to streamline the containerization workflow for Java developers.

Below are some of the key reasons why you should consider using Jib:

  1. Simplicity: Jib simplifies the containerization process by abstracting away the complexities of writing and maintaining Dockerfiles. You don’t need to have Docker knowledge or manage Dockerfile configurations. Jib integrates directly with your build system (Maven, Gradle) and provides a plugin that handles the containerization process for you.
  2. Fast and Incremental Builds: Jib performs fast and efficient builds by leveraging layer caching and only rebuilding the necessary layers when your application’s dependencies or code change. This reduces build times significantly compared to traditional container build processes.
  3. Efficient Image Layering: Jib intelligently layers your application and its dependencies, optimizing the resulting container image size. It separates the application classes, dependencies, and resources into separate layers, allowing for efficient caching, distribution, and reuse of common layers.
  4. No Docker Daemon Required: With Jib, you can build container images directly without requiring a local Docker daemon. This is particularly useful in development environments where Docker might not be installed or when you want to avoid the overhead of interacting with Docker.
  5. Integration with Registry: Jib seamlessly integrates with container registries such as Docker Hub, Google Container Registry, and Amazon ECR. It can directly push the built image to the registry without needing to run separate Docker push commands.
  6. Build Environment Consistency: Jib builds container images in a reproducible and consistent manner, regardless of the local development environment. This ensures that the resulting container images are consistent across different development machines and environments.
  7. Configuration Flexibility: Jib provides a wide range of configuration options to customize your container image. You can specify the base image, set environment variables, define entrypoints, include additional files or resources, and more, giving you fine-grained control over the container image generation.
  8. Build Tool Integration: Jib seamlessly integrates with popular build tools like Maven and Gradle, allowing you to incorporate containerization as part of your existing build process. This makes it easy to adopt Jib into your existing projects without making major changes to your build configuration.

Setting Up Jib in Your Project:

To set up Jib in your Java project, you’ll need to follow a few steps. The instructions may vary slightly depending on whether you’re using Maven or Gradle as your build tool.

Setting up Jib with Maven:

  1. Add the Jib Maven Plugin to your project’s pom.xml file, within the <plugins> section:
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.3.2</version>
<configuration>
<!-- Configure Jib as needed -->
</configuration>
</plugin>

2. Configure Jib within the <configuration> element. You can specify details such as the container registry to push the image to, image tags, and other options. For example:

<configuration>
<to>
<image>registry.hub.docker.com/peerislands/demo-jib</image>
<tags>
<tag>latest</tag>
<tag>1.0.0</tag>
</tags>
<auth>
<username>@userName</username>
<password>@password</password>
</auth>
</to>
</configuration>

3. Build the container image using the following Maven command:

 mvn clean compile jib:build

Setting up Jib with Gradle:

  1. Add the Jib Gradle Plugin to your project’s build.gradle file, within the plugins block:
plugins {
id 'com.google.cloud.tools.jib' version '3.3.2'
}

2. Configure Jib within the jib block. Specify the container registry, image tags, and other options as needed. For example:

jib {
to {
image = 'registry.hub.docker.com/peerislands/demo-jib'
tags = ['latest', '1.0.0']
}
}

3. Build the container image using the following Gradle command:

./gradlew jib

Building Containers with Jib:

Overheads of using Docker Build over Jib

Using Docker Build for container image creation has some overheads compared to using Jib:

Building Containers with Docker
  1. Docker knowledge and Dockerfile management: With Docker Build, you need to have knowledge of Docker and write/maintain Dockerfiles. Dockerfiles can be complex and require understanding of Docker’s syntax and best practices. This adds an extra learning curve and maintenance burden, especially for developers less familiar with Docker.
  2. Docker daemon and dependencies: Docker Build requires a Docker daemon to be running on the local machine or build server. This means you need to have Docker installed and properly configured, which might not always be the case, especially in certain development environments or CI/CD systems. Additionally, Docker Build may have dependencies on the host system, which can increase the build complexity.
  3. Layer caching limitations: Docker Build utilizes layer caching to speed up subsequent builds. However, the layer caching mechanism is limited to the contents of the Dockerfile and its immediate dependencies. If there are changes in your application code or dependencies outside the Dockerfile, Docker Build will rebuild all layers, which can result in slower build times.
  4. Image size optimization: Docker Build might require additional steps and techniques (like multi-stage builds) to optimize the resulting image size. Managing image layers and minimizing the inclusion of unnecessary dependencies can be a manual and error-prone process.

Jib, on the other hand, mitigates these overheads by providing a simpler and streamlined approach to container image creation. It abstracts away the complexities of Dockerfile management, works without requiring a Docker daemon, optimizes build times with layer caching, automatically optimizes image size, and seamlessly integrates with container registries.

Jib to rescue

Build Containers with Jib

Below are some of the advantages of Jib:

  1. Analyzing Dependencies: Jib analyzes your project’s dependencies, including the application JAR file and any additional runtime dependencies declared in your build configuration. It captures the necessary files and libraries required to run your application.
  2. Optimized Layer Generation: Jib adopts a layered approach to container image building. It analyzes the project’s dependencies and breaks them down into discrete layers. This approach allows for efficient caching and incremental builds, as Jib only rebuilds the necessary layers when changes occur, rather than rebuilding the entire image. It intelligently organizes the layers based on the dependencies and changes in the application code. It ensures that the layers containing less frequently changing dependencies are placed higher in the layer stack. This optimization helps in reducing build times and improving the efficiency of image updates.
  3. Layer Caching: Layer caching is a powerful feature of Jib that significantly speeds up subsequent builds. During the initial build, Jib builds and pushes each layer individually to the container registry. For subsequent builds, Jib only rebuilds and pushes the layers that have changed since the last build, while reusing the unchanged layers from the cache. This caching mechanism minimizes the need to rebuild and reupload the entire application for every build, resulting in faster build times.
  4. Incremental Build: Jib uses an incremental build approach, where it tracks changes to your application’s files and dependencies. This allows Jib to determine which parts of your application have been modified since the last build. By only rebuilding and pushing the modified parts, Jib further reduces the build time.

By leveraging layer caching and incremental build techniques, Jib minimizes the time required to build and deploy container images, especially during subsequent builds. This helps to improve development productivity by eliminating the need to rebuild unchanged parts of the application and speeding up the container image generation process.

Container Registry & CI/CD Integration:

When using Jib to build container images, you can seamlessly integrate with various container registries to store and distribute your images. Jib provides built-in support for popular container registries such as Docker Hub, Google Container Registry (GCR), Amazon Elastic Container Registry (ECR), and others

1. Configure the Registry: Start by configuring the container registry in your build tool’s configuration file (pom.xml for Maven or build.gradle for Gradle). You need to specify the registry URL, username, and password for authentication.

For example, in Maven:

<configuration>
<to>
<image>your-registry/your-project</image>
<auth>
<username>username</username>
<password>password</password>
</auth>
</to>
</configuration>

Jib will build the container image and automatically push it to the specified container registry, using the provided authentication credentials.

2. Additional Configuration: Depending on the container registry, you may need to specify additional configuration options. For example, if you’re using Google Container Registry (GCR), you can configure the project ID and the region. Refer to the Jib documentation for registry-specific configuration details.

CI/CD Integration

Jib seamlessly integrates with popular CI/CD tools such as Jenkins, GitLab CI/CD, AWS CodePipeline, and others. It can be easily added as a build step or plugin in the pipeline configuration. Integration plugins and extensions are available for different CI/CD tools, providing out-of-the-box support for Jib.

Building Container Variants:

When using Jib to build container images for your Java project, you have the ability to create different container variants. Container variants allow you to build images tailored for specific environments, configurations, or deployment scenarios.

By defining and building container variants, you can generate multiple container images from the same project with different configurations. This allows you to create images optimized for different environments, deployment scenarios, or specific requirements. You can choose the appropriate variant based on your deployment needs, making it easier to manage and distribute container images tailored to different use cases.

Quick overview of building container variants with Jib

  1. Configuration for Container Variants: Start by defining the configurations for your container variants. These configurations can be specified in your build tool’s configuration file (pom.xml for Maven or build.gradle for Gradle) under the Jib plugin configuration section.
  2. Configure Variants: Within the Jib plugin configuration, you can define multiple <container> elements to represent different container variants. Each variant can have its own set of configurations, such as a different base image, exposed ports, environment variables, entrypoint, and more.

For example, in Maven:

<configuration>
<container>
<name>development</name> <!-- Variant name: development -->
<from>
<image>openjdk:11-jre</image>
</from>
<ports>
<port>8080</port>
</ports>
<environment>
<APP_ENV>production</APP_ENV>
</environment>
<!-- Other configurations for development -->
</container>
<container>
<name>production</name> <!-- Variant name: production -->
<from>
<image>openjdk:8-jre-alpine</image>
</from>
<ports>
<port>8080</port>
<port>9090</port>
</ports>
<!-- Other configurations for production -->
</container>
</configuration>

In the example above, two container variants, “development” and “production,” are defined within the <containers> section. Each variant can have its own set of configurations. The <name> element within each <container> element represents the variant name.

To build a specific variant, you can use the -Djib.container parameter during the Maven build command. For example: In the below command, the variant with the name “development” will be built.

mvn compile jib:build -Djib.container=development

Jib for k8

Jib provides seamless integration with Kubernetes, simplifying the container build and deployment process for Java applications.

  1. Dockerfile-Free Build: Jib eliminates the need for writing and maintaining Dockerfiles. Instead, it directly builds container images from your Java project without requiring any Dockerfile configuration. This makes the containerization process more streamlined and eliminates the complexities of managing Dockerfiles.
  2. Integration with Container Registries: Jib seamlessly integrates with container registries, including Docker Hub, Google Container Registry (GCR), and AWS Elastic Container Registry (ECR). It provides easy configuration options to push the built container images directly to these registries.
  3. Kubernetes-Optimized Image Configuration: Jib automatically optimizes the container images for Kubernetes deployments. It applies best practices, such as adding only the necessary dependencies and resources to the image, resulting in smaller image sizes and improved resource utilization within the Kubernetes cluster.
  4. Compatibility with Kubernetes Deployment Manifests: Once the container images are built with Jib, they can be easily deployed to Kubernetes using standard Kubernetes deployment manifests. You can use deployment YAML files, such as Deployment, StatefulSet, or DaemonSet, to define the desired Kubernetes deployment configuration.

These features make Jib an excellent choice for Java developers looking to deploy their applications to Kubernetes clusters.

Conclusion

Jib is a valuable tool that empowers Java developers to build containers efficiently and effortlessly. By leveraging Jib, developers can focus more on writing code and iterating on their Java applications, rather than dealing with the complexities of Dockerfile configurations.

Its ability to abstract away Dockerfile complexities, optimize images, and seamlessly integrate with Kubernetes and cloud platforms makes it a must-have tool in your containerization toolkit.

Give Jib a try and experience the simplicity and efficiency it brings to your container building process.

--

--