HomeAboutArchivesTools & ResourcesSupport me
Hi! 👋 I'm Szymon

I help you become a better software developer.

  • 1.15kFollowers
  • 2.36kSubscribers
  • 110Followers
  • 30.2kReputation

Latest posts from the Jenkins Pipeline Cookbook

Jenkins Declarative Pipeline with the dynamic agent - how to ...
5 Common Jenkins Pipeline Mistakes
How to catch curl response in Jenkins Pipeline?
How to time out Jenkins Pipeline stage and keep the pipeline ...
Jenkins Scripted Pipeline vs. Declarative Pipeline - the 4 pr...
Using Jenkins Pipeline parallel stages to build Maven project...
Building Java and Maven docker images using parallelized Jenk...
More

Popular categories

  • Groovy Cookbook28
  • Jenkins Pipeline Cookbook9
  • Programmer's Bookshelf6
  • Micronaut Cookbook4
  • Ratpack Cookbook4
  • Learning Java4
  • jq cookbook3
  • How to3
  • Blog Reports2

Don't miss anything - join my newsletter

Additional materials and updates for subscribers. No spam guaranteed.
Unsubscribe at any time.

Did you like this article?

Spread the !
  • ☕️
  1. e.printstacktrace.blog
  2. Jenkins Pipeline Cookbook

Building Java and Maven docker images using parallelized Jenkins Pipeline and SDKMAN!

  • November 11, 2019
  • 6 min. read
  • 0 Comments

In the last article, I have shown you how you can build a docker image for Jenkins Pipeline using SDKMAN! command-line tool. Today I will show you how you can build multiple different docker images using parallelized Jenkins Pipeline.

Why Maven and Java?

Before we move forward, let me explain why I use Maven and Java docker image in this example. There is an official Maven docker hub repository where you can download a specific Maven base image based on a particular Java version. It makes sense because you cannot use Maven without Java. However, this might become a bottleneck if you want to create your custom image (e.g., you need to install some additional tools that are missing in the official Maven image), and support different Maven versions at the same time. That is why we want to use a single Dockerfile to build, let’s say, three images with different Java inside — Amazon Corretto 11, Azul Zulu 13, and GraalVM CE 19.2.1.

Dockerfile

Here is the Dockerfile we have prepared in the previous blog post.

Listing 1. Dockerfile
FROM debian:stretch-slim

# Defining default Java and Maven version
ARG JAVA_VERSION="11.0.5-amzn"
ARG MAVEN_VERSION="3.6.2"

# Defining default non-root user UID, GID, and name
ARG USER_UID="1000"
ARG USER_GID="1000"
ARG USER_NAME="jenkins"

# Creating default non-user
RUN groupadd -g $USER_GID $USER_NAME && \
	useradd -m -g $USER_GID -u $USER_UID $USER_NAME

# Installing basic packages
RUN apt-get update && \
	apt-get install -y zip unzip curl && \
	rm -rf /var/lib/apt/lists/* && \
	rm -rf /tmp/*

# Switching to non-root user to install SDKMAN!
USER $USER_UID:$USER_GID

# Downloading SDKMAN!
RUN curl -s "https://get.sdkman.io" | bash

# Installing Java and Maven, removing some unnecessary SDKMAN files
RUN bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && \
    yes | sdk install java $JAVA_VERSION && \
    yes | sdk install maven $MAVEN_VERSION && \
    rm -rf $HOME/.sdkman/archives/* && \
    rm -rf $HOME/.sdkman/tmp/*"

ENTRYPOINT bash -c "source $HOME/.sdkman/bin/sdkman-init.sh && $0 [email protected]"

We specify JAVA_VERSION and MAVEN_VERSION using ARG for one important reason — we want to allow overriding those values using --build-arg command-line parameter.

Jenkins Pipeline

We are going to build three docker images containing different Java distribution. We could hardcode all different variants inside the Jenkins Pipeline code, but it could make the maintenance more problematic. It would be much better if we decouple the Jenkins Pipeline logic from the version variants we want to build ultimately. We could use YAML to declare all the images we want to build in the pipeline.

Listing 2. versions.yml
images:
  "3.6-amazoncorretto-11":
    java: 11.0.5-amzn
    maven: 3.6.2
    tags:
      - 3.6.2-amazoncorretto-11.0.5
      - 3.6-amazoncorretto-11

  "3.6-zulu-13":
    java: 13.0.1-zulu
    maven: 3.6.2
    tags:
      - 3.6.2-zulu-13.0.1
      - 3.6-zulu-13
      - latest

  "3.6-graalvm-19":
    java: 19.2.1-grl
    maven: 3.6.2
    tags:
      - 3.6.2-graalvm-19.2.1
      - 3.6-graalvm-19

The format for this file is straightforward. We define a Java version, Maven version, and a list of docker tags we want to use for each specific variant.

Having docker image variants decoupled from the pipeline, we can now implement a simple Jenkins Pipeline that will build those images in parallel.

Listing 3. Jenkinsfile
pipeline {
    agent any

    environment {
        IMAGE_NAME = "mymaven" (1)
    }

    stages {
        stage("Build docker images") {
            steps {
                script {
                    def versions = readYaml file: "versions.yml" (2)

                    def stages = versions.images.collectEntries { label, props -> (3)
                        [(label): {
                            stage(label) {
                                sh """docker build \
                                --build-arg JAVA_VERSION=${props.java} \
                                --build-arg MAVEN_VERSION=${props.maven} \
                                ${collectTags(props.tags, env.IMAGE_NAME)} \
                                .
                            """
                            }
                        }]
                    }

                    parallel stages (4)
                }
            }
        }
    }
}

@NonCPS
String collectTags(final List<String> tags, final String imageName) {
    return tags.collect { tag -> "-t ${imageName}:${tag}" }.join(" ")
}

This pipeline has only a single stage that executes three nested stages in parallel. Each parallelized stage is responsible for building and tagging one specific variant of mymaven docker image . We use readYaml pipeline utility step to read images configuration from the versions.yml file . Then we construct the stage for every image to run in parallel .

When we execute this pipeline, we get something like this.

Every parallel stage has built a different docker image variant.

# 3.6-amazoncorretto-11 stage:
+ docker build --build-arg JAVA_VERSION=11.0.5-amzn --build-arg MAVEN_VERSION=3.6.2 -t mymaven:3.6.2-amazoncorretto-11.0.5 -t mymaven:3.6-amazoncorretto-11 .

# 3.6-graalvm-19 stage:
+ docker build --build-arg JAVA_VERSION=19.2.1-grl --build-arg MAVEN_VERSION=3.6.2 -t mymaven:3.6.2-graalvm-19.2.1 -t mymaven:3.6-graalvm-19 .

# 3.6-zulu-13 stage:
+ docker build --build-arg JAVA_VERSION=13.0.1-zulu --build-arg MAVEN_VERSION=3.6.2 -t mymaven:3.6.2-zulu-13.0.1 -t mymaven:3.6-zulu-13 -t mymaven:latest .

We can list existing mymaven docker images.

$ docker images | grep mymaven
mymaven            3.6-graalvm-19                32a1ea1dc8ee        38 minutes ago      1.01 GB
mymaven            3.6.2-graalvm-19.2.1          32a1ea1dc8ee        38 minutes ago      1.01 GB
mymaven            3.6-zulu-13                   8553ca3e7556        41 minutes ago      439 MB
mymaven            3.6.2-zulu-13.0.1             8553ca3e7556        41 minutes ago      439 MB
mymaven            latest                        8553ca3e7556        41 minutes ago      439 MB
mymaven            3.6-amazoncorretto-11         1d38b0879ab0        5 days ago          407 MB
mymaven            3.6.2-amazoncorretto-11.0.5   1d38b0879ab0        5 days ago          407 MB

And as the final step, we can execute mvn -version from each docker image to verify that everything worked.

$ docker run --rm -u $(id -u) mymaven:3.6-amazoncorretto-11 mvn -version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-27T15:06:16Z)
Maven home: /home/jenkins/.sdkman/candidates/maven/current
Java version: 11.0.5, vendor: Amazon.com Inc., runtime: /home/jenkins/.sdkman/candidates/java/11.0.5-amzn
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "5.3.8-200.fc30.x86_64", arch: "amd64", family: "unix"

$ docker run --rm -u $(id -u) mymaven:3.6-graalvm-19 mvn -version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-27T15:06:16Z)
Maven home: /home/jenkins/.sdkman/candidates/maven/current
Java version: 1.8.0_232, vendor: Oracle Corporation, runtime: /home/jenkins/.sdkman/candidates/java/19.2.1-grl/jre
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "5.3.8-200.fc30.x86_64", arch: "amd64", family: "unix"

$ docker run --rm -u $(id -u) mymaven:3.6-zulu-13 mvn -version
Apache Maven 3.6.2 (40f52333136460af0dc0d7232c0dc0bcf0d9e117; 2019-08-27T15:06:16Z)
Maven home: /home/jenkins/.sdkman/candidates/maven/current
Java version: 13.0.1, vendor: Azul Systems, Inc., runtime: /home/jenkins/.sdkman/candidates/java/13.0.1-zulu
Default locale: en_US, platform encoding: ANSI_X3.4-1968
OS name: "linux", version: "5.3.8-200.fc30.x86_64", arch: "amd64", family: "unix"
You can download the source code presented in this blog post from the following Github repository — https://github.com/wololock/sdkman-docker-pipeline-example.

Jenkins Pipeline Maven build - how to set it up? | #jenkinspipeline #maven

Building a continuous integration Jenkins pipeline for the Maven-based Java project was never easier. You can start by using mvn installed on the Jenkins node, and then you can slowly migrate to a more flexible solution - dockerized builds using either "docker" agent, or the "dockerfile" one. In this video, I show you how quickly you can start building a Maven project in the Jenkins pipeline, and when you should consider improving by including docker containers to your workflow. Watch now »

  • java
  • groovy
  • docker
  • sdkman
  • devops
  • jenkins
  • jenkins-pipeline
  • cicd
  • maven

How to

Using CircleCI to deploy Hexo blog to GitHub Pages - how to set it up?

  • November 17, 2019
  • 6 min. read
  • 0 Comments

I was using Travis CI to execute 271 builds and deployments of this blog. Last Friday, I decided to experiment with CircleCI and see if this could be a viable alternative to my current solution. In this blog post, I explain why I decided to switch, and how to set up CircleCI to deploy Hexo blog to the GitHub Pages without much hustle.

Jenkins Pipeline Cookbook

Using SDKMAN! as a docker image for Jenkins Pipeline - a step by step guide

  • November 6, 2019
  • 6 min. read
  • 0 Comments

A few days ago, I was struggling with some Docker images I use in my Jenkins CI environment. I r...

Jenkins Pipeline Cookbook

Using Jenkins Pipeline parallel stages to build Maven project with different JDKs

  • November 28, 2019
  • 6 min. read
  • 0 Comments

In one of the latest blog posts, I have shown you how you can build a Docker image with Java and...

Jenkins Pipeline Cookbook

How to time out Jenkins Pipeline stage and keep the pipeline running?

  • April 16, 2020
  • 6 min. read
  • 0 Comments

The declarative Jenkins Pipeline allows us to define timeout either at the pipeline level or the...

Any thoughts or ideas?

Let's talk in the comment's section 💬

Want to put a code sample in the comment? Read the Syntax highlighting guide for more information.
Empty
Latest blog posts
  • Merging JSON files recursively in the command-line
  • Jenkins Declarative Pipeline with the dynamic agent - how to configure it?
  • Groovy Ecosystem Usage Report (2020)
  • How to convert JSON to CSV from the command-line?
  • 5 Common Jenkins Pipeline Mistakes
  • How to merge two maps in Groovy?
  • Building stackoverflow-cli with Java 11, Micronaut, Picocli, and GraalVM
  • How to catch curl response in Jenkins Pipeline?
  • Atomic Habits - book review
  • Parsing JSON in command-line with jq: basic filters and functions (part 1)
Trending videos
How to merge two JSON files in the command-line using jq? | #jq #json #curl

In this jq tutorial video, I show you how you can merge two JSON files in the command-line using jq JSON processor. I explain...

Building command-line app with Java 11, Micronaut, Picocli, and GraalVM | #micronaut

In this video, I will show you how to create a standalone command-line application (CLI app) using Java 11, Micronaut, Picocl...

Useful links
  • Start here
  • About
  • Archives
  • Resources
  • Privacy Policy
  • Merchandise
  • My Kit
  • RSS
  • Support the blog
Popular categories
  • Groovy Cookbook28
  • Jenkins Pipeline Cookbook9
  • Programmer's Bookshelf6
  • Micronaut Cookbook4
  • Ratpack Cookbook4
  • Learning Java4
  • jq cookbook3
  • How to3
  • Blog Reports2
Popular tags
affiliate async benchmark blogging book career cicd continuous-integration curl devops docker git github graalvm gradle grails groovy haskell hexo java java-8 jenkins jenkins-pipeline jenkinsfile jmh jq json junit learning maven metaprogramming micronaut native-image non-blocking progress ratpack reactive-programming reading recursion review rxjava sdkman session split spock stackoverflow string tail-call tail-recursion unit-test
  • Designed by @wololock
  • Created with Hexo
  • Hosted on GitHub
  • Deployed with Circle CI
  • License CC BY-NC-SA 4.0