Building Docker images is a very common workflow for microservice-based architectures. Imagine you wanted to create and push an image for a web application based on the Spring Boot framework. Listing 1 shows the basic setup of a plain Spring Boot application.
plugins {
id 'java'
id 'org.springframework.boot' version '2.0.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.6.RELEASE'
}
repositories {
jcenter()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtime 'org.postgresql:postgresql:42.2.5'
}
Listing 1. Building a Spring Boot application with Gradle
Adding Jib to the build process is simple. Just apply the Jib Gradle plugin with a specific version. Optionally, you can also provide custom configuration to control the runtime behavior of the plugin. Listing 2 shows how to enhance the existing build script by applying the Jib plugin and providing a tag for the image.
plugins {
id 'com.google.cloud.tools.jib' version '0.9.11'
}
jib.to.image = 'bmuschko/my-java-app:1.0'
Listing 2. Declaring and configuring the Jib Gradle plugin
With these 4 lines of code in place, it is already possible to execute the containerization workflow by running the jib
task. The following output should give you a hint on its inner workings:
$ ./gradlew jib --console=verbose
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
warning: Base image 'gcr.io/distroless/java' does not use a specific image digest - build may not be reproducible
Containerizing application to bmuschko/java-app-jib:1.0...
Retrieving registry credentials for registry.hub.docker.com...
Getting base image gcr.io/distroless/java...
Building dependencies layer...
Building resources layer...
Building classes layer...
Finalizing...
> Task :jib
Container entrypoint set to [java, -cp, /app/resources:/app/classes:/app/libs/*, com.bmuschko.todo.webservice.Application]
Built and pushed image as bmuschko/java-app-jib:1.0
You can see in the console output that the tool creates separate layers for the application dependencies, the resource files and the class files. Jib also determines the main class name by scanning the classpath.
Based on the provided image name, Jib identifies that the image should be pushed to Docker Hub, retrieves my stored credentials with the help of docker-credential-helpers and finally performs the operation. You can verify that Jib didn’t actually create an image via the Docker engine by running docker images
. There’s no image with the tag bmuschko/java-app-jib:1.0
to be found.
Building and pushing images independent of the Docker engine can be extremely powerful. Jib completely abstracts the implementation details from the developer. There’s no need to fully understand the details. You can simply trust that Jib produces the desired outcome. Avoiding the need to install Docker is highly beneficial in CI/CD environments. CI agents can perform containerization tasks without the burden of setting up and maintaining yet another tool.