DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Spring Boot With Kubernetes
  • Containerization and Helm Templatization Best Practices for Microservices in Kubernetes
  • Why Camel K?
  • Configuring Graceful-Shutdown, Readiness and Liveness Probe in Spring Boot 2.3.0

Trending

  • AI’s Role in Everyday Development
  • Performance Optimization Techniques for Snowflake on AWS
  • Concourse CI/CD Pipeline: Webhook Triggers
  • Medallion Architecture: Efficient Batch and Stream Processing Data Pipelines With Azure Databricks and Delta Lake
  1. DZone
  2. Software Design and Architecture
  3. Microservices
  4. Create Fast and Easy Docker Images With Jib

Create Fast and Easy Docker Images With Jib

In this article, create Docker images with Jib.

By 
Gunter Rotsaert user avatar
Gunter Rotsaert
DZone Core CORE ·
Feb. 14, 20 · Tutorial
Likes (6)
Comment
Save
Tweet
Share
22.4K Views

Join the DZone community and get the full member experience.

Join For Free

In this post, we are going to take a look at Jib, a tool from Google in order to create Docker images in an easy and fast way. No need to create a Docker file, no need to install a Docker daemon, Jib just runs out-of-the-box.

1. Introduction

Up until now, we have been using the dockerfile-maven-plugin from Spotify in order to build and push our Docker images. This requires us to write a Docker file, according to best practices, to install a Docker daemon and to add the plugin to our build process. Jib will provide us a more easy way to create our Docker images. We only need to add and configure the Maven plugin and that is about it. Of course, we only believe this when we have tried it ourselves, and that is exactly what we are going to do.

We will create a simple Spring Boot application, containerize it with Jib Maven plugin and push it to Docker Hub. Next, we will pull the image and run the Docker container. The sources are available at GitHub.

We are using:

  • Ubuntu 18.04
  • Spring Boot 2.2.1
  • Java 11
  • Jib Maven Plugin 1.8.0
  • An account at Docker Hub

More information about Jib can be found at the Google Cloud Platform Blog and at GitHub.

You might also want to read: Publish Docker Images on a Private Nexus Repository Using Jib Maven Plugin

2. Create the Application

First, we will create a simple Spring Boot application. We add the Spring Actuator and Spring Web MVC dependencies to our pom. Spring Actuator will provide us the means to add health checks.

XML
 




xxxxxxxxxx
1


 
1
<dependency>
2
  <groupId>org.springframework.boot</groupId>
3
  <artifactId>spring-boot-starter-actuator</artifactId>
4
</dependency>
5
<dependency>
6
  <groupId>org.springframework.boot</groupId>
7
  <artifactId>spring-boot-starter-web</artifactId>
8
</dependency>



Our application consists out of a Rest controller which returns a hello message and the address of the machine.

Java
 




xxxxxxxxxx
1
16


 
1
@RestController
2
public class HelloController {
3
 
4
    @RequestMapping("/hello")
5
    public String hello() {
6
        StringBuilder message = new StringBuilder("Hello Jib Maven Plugin!");
7
        try {
8
            InetAddress ip = InetAddress.getLocalHost();
9
            message.append(" From host: " + ip);
10
        } catch (UnknownHostException e) {
11
            e.printStackTrace();
12
        }
13
        return message.toString();
14
    }
15
 
16
}



Run the application locally:

Shell
 




xxxxxxxxxx
1


 
1
$ mvn spring-boot:run



After successful startup, we invoke the URL http://localhost:8080/hello which returns us the following message:

Shell
 




xxxxxxxxxx
1


 
1
Hello Jib Maven Plugin! From host: gunter-Latitude-5590/127.0.1.1



3. Setup Jib and Docker Hub

In this section, we will add the Jib Maven plugin and ensure that we have a successful connection to Docker Hub Registry. It has been quite a struggle to get this working properly, mainly due to a lack of documentation. The official Jib documentation is quite vague about secure authentication methods. Most of the examples consist of adding plain text credentials to the pom or to the Maven settings file. But that is not what we want. We want a secure way of connecting to Docker Hub by means of a Docker Credential Helper.

In order to test the connection, we add the Jib Maven plugin to our pom and configure it in order to retrieve a base image and to push this image to Docker Hub.

XML
 




xxxxxxxxxx
1
15


 
1
<plugin>
2
  <groupId>com.google.cloud.tools</groupId>
3
  <artifactId>jib-maven-plugin</artifactId>
4
  <version>1.8.0</version>
5
  <configuration>
6
    <!-- openjdk:11.0.5-jre -->
7
    <from>
8
      <image>openjdk:11.0.5-jre</image>
9
    </from>
10
    <to>
11
      <image>docker.io/${docker.image.prefix}/${project.artifactId}</image>
12
      <credHelper>pass</credHelper>
13
    </to>
14
  </configuration>
15
</plugin>



The from tag contains our base image, just like the FROM statement in a Docker file. The to tag contains the image we want to push. The ${docker.image.prefix} is set to mydeveloperplanet (our Docker Hub account), you will need to change this to your own account. The ${project.artifactId} contains the version 1.0-SNAPSHOT. In order to make use of a Credential Helper, we set the tag credHelper to pass.

Before starting, we need to set up a GPG key if you do not already have one, see also the Ubuntu help pages.

Shell
 




xxxxxxxxxx
1


 
1
$ gpg --gen-key



For ease of use, you can add the generated key to your profile as an environment variable. Add the following line to your .profile where you replace Your_GPG_Key with your key.

Shell
 




xxxxxxxxxx
1


 
1
export GPGKEY=Your_GPG_Key



Source your .profile in order to make the environment variable available.

Shell
 




xxxxxxxxxx
1


 
1
$ source .profile



You can also choose to send your key to the Ubuntu keyserver, but it is not necessary in order to execute the next steps.

Shell
 




xxxxxxxxxx
1


 
1
$ gpg --send-keys --keyserver keyserver.ubuntu.com $GPGKEY



Install pass and initialize a password store with your GPG key.

Shell
 




xxxxxxxxxx
1


 
1
$ sudo apt install pass
2
$ pass init Your_GPG_Key
3
 
4
mkdir: created directory '/home/gunter/.password-store/'
5
Password store initialized for My Password Storage Key



Next thing to do, is to download and unpack the Docker Credential Helper and make the file executable.

Shell
 




xxxxxxxxxx
1


 
1
$ wget https://github.com/docker/docker-credential-helpers/releases/download/v0.6.3/docker-credential-pass-v0.6.3-amd64.tar.gz
2
$ tar xvzf docker-credential-pass-v0.6.3-amd64.tar.gz
3
$ mv docker-credential-pass /usr/bin
4
$ chmod +x docker-credential-pass



The Docker Credential Helper needs to be configured correctly and this is where documentation falls short.

Create a config.json file with the following content. In the documentation it is stated to add the contents { "credStore": "pass" }, but with this configuration, Jib will not be able to connect to the Docker Hub Registry. We found the following issue where the use of credStore is not supported anymore for the Google Cloud Registry.

JSON
 




xxxxxxxxxx
1


 
1
"credHelpers": {
2
"https://index.docker.io/v1": "pass"
3
}



Initialize the Docker Credential Helper. Enter the password pass is initialized when being asked for a password.

Shell
 




xxxxxxxxxx
1


 
1
$ pass insert docker-credential-helpers/docker-pass-initialized-check
2
mkdir: created directory '/home/gunter/.password-store/docker-credential-helpers'
3
Enter password for docker-credential-helpers/docker-pass-initialized-check:
4
Retype password for docker-credential-helpers/docker-pass-initialized-check:



Check whether the password is correctly set:

Shell
 




xxxxxxxxxx
1


 
1
$ pass show docker-credential-helpers/docker-pass-initialized-check
2
pass is initialized



Login with your Docker credentials. A warning is raised saying that your password is stored unencrypted in the file config.json. We could not figure out why this warning is being raised, because the credentials are stored encrypted in the config.json file.

Shell
 




xxxxxxxxxx
1


 
1
$ docker login
2
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
3
Username: your_user_name
4
Password: 
5
WARNING! Your password will be stored unencrypted in /home/gunter/.docker/config.json.
6
Configure a credential helper to remove this warning. See
7
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
8
 
9
Login Succeeded



From now on, it is possible to execute docker login without the need for entering your credentials.

Shell
 




xxxxxxxxxx
1


 
1
$ docker login
2
Authenticating with existing credentials...
3
WARNING! Your password will be stored unencrypted in /home/gunter/.docker/config.json.
4
Configure a credential helper to remove this warning. See
5
https://docs.docker.com/engine/reference/commandline/login/#credentials-store
6
 
7
Login Succeeded



You can logout again with docker logout:

Shell
 




xxxxxxxxxx
1


 
1
$ docker logout
2
Removing login credentials for https://index.docker.io/v1/



Ensure that you are logged in again and run the Maven Jib build command:

Shell
 




xxxxxxxxxx
1


 
1
$ mvn compile jib:build



The image is successfully built and pushed to Docker Hub. Two warnings are raised during the build:

Base image 'openjdk:11.0.5-jre' does not use a specific image digest - build may not be reproducible
This can be easily be solved by replacing openjdk:11.0.5-jre with the sha256 key for the base image openjdk@sha256:b3e19d27caa8249aad6f90c6e987943d03e915bbf3a66bc1b7f994a4fed668f6

The credential helper (docker-credential-pass) has nothing for server URL: https://index.docker.io/v1
This is a strange warning because the credentials for this URL are resolved and used for pushing the image.

4. Configure Jib for Our Application

Now that we have configured the authentication in a secure way, we can continue with configuring the Jib Maven plugin for our application. We add a tag to our image and specifiy the main class.

XML
 




xxxxxxxxxx
1
10


 
1
<to>
2
  <image>docker.io/${docker.image.prefix}/${project.artifactId}</image>
3
  <credHelper>pass</credHelper>
4
  <tags>
5
    <tag>${project.version}</tag>
6
  </tags>
7
</to>
8
<container>
9
  <mainClass>com.mydeveloperplanet.myjibplanet.MyJibPlanetApplication</mainClass>
10
</container>



Do not add the tag format with value OCI to your container configuration. Docker Hub does not support yet OCI completely and an error message will be shown ‘An error occurred while loading the tags. Try reloading the page’.

Build the image again and pull the Docker image:

Shell
 




xxxxxxxxxx
1
15


 
1
$ docker pull mydeveloperplanet/myjibplanet
2
Using default tag: latest
3
latest: Pulling from mydeveloperplanet/myjibplanet
4
844c33c7e6ea: Pull complete 
5
ada5d61ae65d: Pull complete 
6
f8427fdf4292: Pull complete 
7
a5217f27a28f: Pull complete 
8
176e83ebae4f: Pull complete 
9
800204250483: Pull complete 
10
492e142ab90b: Pull complete 
11
7c8e6198cd4b: Pull complete 
12
c49bb7f02774: Pull complete 
13
Digest: sha256:b7144bfdf6ee47d6b38914a84789ef9f7e2117320080b28ce39c385ee399a0c8
14
Status: Downloaded newer image for mydeveloperplanet/myjibplanet:latest
15
docker.io/mydeveloperplanet/myjibplanet:latest



Run the image and map it to port 8080:

Shell
 




xxxxxxxxxx
1


 
1
$ docker run -p 127.0.0.1:8080:8080/tcp mydeveloperplanet/myjibplanet
2
...
3
2019-12-25 09:57:13.196 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
4
2019-12-25 09:57:13.205 INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 9 ms



List the Docker containers:

Shell
 




xxxxxxxxxx
1


 
1
$ docker ps
2
CONTAINER ID    IMAGE                           COMMAND                  CREATED                 STATUS           PORTS                      NAMES
3
c05e431b0bd1    mydeveloperplanet/myjibplanet   "java -cp /app/resou…"   13 seconds ago    Up 12 seconds    127.0.0.1:8080->8080/tcp   recursing_meninsky



We only need to retrieve the IP address of our Docker container:

JSON
 




xxxxxxxxxx
1


 
1
$ docker inspect c05e431b0bd1
2
...
3
  "NetworkSettings": {
4
    ...
5
    "IPAddress": "172.17.0.2",
6
  ...
7
  }
8
...



The URL of our application can now be invoked with http://172.17.0.2:8080/hello.

This returns us the welcome message:

Shell
 




xxxxxxxxxx
1


 
1
Hello Jib Maven Plugin! From host: c05e431b0bd1/172.17.0.2



We have one more issue to solve: our application runs as root in the Docker container. This is not something we want because of security. First, we will check which users are available in the Docker container:

Shell
 




xxxxxxxxxx
1


 
1
$ docker exec -it -u root c05e431b0bd1 cat /etc/passwd
2
...
3
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
4
...



The Docker container contains a user nobody, which is the one we can use for running our application. Add the user tag to the pom:

XML
 




xxxxxxxxxx
1


 
1
<container>
2
  <mainClass>com.mydeveloperplanet.myjibplanet.MyJibPlanetApplication</mainClass>
3
  <user>nobody</user>
4
</container>



Build the image, pull it and run it. Verify with docker inspect whether nobody is used as user.

JSON
 




xxxxxxxxxx
1


 
1
...
2
  "Config": {
3
    "Hostname": "76b3afaca3af",
4
    "Domainname": "",
5
    "User": "nobody",
6
    ...
7
  }
8
...



In our pom, we also added Spring Actuator. There is no option to add a Docker healthcheck via Jib. This must be resolved with liveness probe and readiness probe in the Kubernetes configuration, see also this issue.

5. Conclusion

We experimented with Jib Maven plugin in order to create our Docker images. Configuring the credentials for Docker Hub Registry was a real struggle, but once this was set up, the plugin was really easy to use. Besides that, no Docker daemon is needed and you do not need to write a separate Docker file. Last but not least, it is really fast. We will definitely be using this plugin in the near future.

Docker (software) Spring Framework shell Kubernetes application Spring Boot Apache Maven

Published at DZone with permission of Gunter Rotsaert, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Spring Boot With Kubernetes
  • Containerization and Helm Templatization Best Practices for Microservices in Kubernetes
  • Why Camel K?
  • Configuring Graceful-Shutdown, Readiness and Liveness Probe in Spring Boot 2.3.0

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!