Build and Publish Docker Image to an External Repository with Jenkins Agent on Openshift

In this tutorial, we will do a very basic setup to build and publish Docker Image to an external Docker Registry with Jenkins Agent running on Openshift. We will use this Maven project as the example here.
Thus, you are expected to have basic knowledge of Jenkins, Openshift, and Docker as well as Maven to be able to follow up with this tutorial.

At the end of this tutorial, our pipeline will be able to do the below:

  1. Spin up a Jenkins Slave pod on Openshift
  2. Check out the target Maven project inside the Jenkins Slave pod and execute the maven install command
  3. Trigger Openshift Build from the Jenkins Slave pod to build the image with the provided Dockerfile inside the sample project. Besides, this also helps to push the image to an external Docker Registry

Prerequisite

Make sure the Jenkins server is accessible from the Openshift cluster and vice versa.

Get Openshift Ready

  1. Create your ci-test namespace:
oc new-project ci-test

2. Create a service account called jenkinsand give it the necessary permissions

oc create serviceaccount jenkinsoc adm policy add-cluster-role-to-user edit -z jenkinsoc adm policy add-scc-to-user anyuid -z jenkins

3. Print out and store the service account token for later use

oc serviceaccounts get-token jenkins -n ci-test

4. Since we want to push our image to an external Docker registry, we need a Secretto store the credential to access the target Docker registry

oc create secret generic secret-2-docker --from-file=.dockerconfigjson=<path-to-your-dockerconfigjson> --type=kubernetes.io/dockerconfigjson

Whereas, the content of .dockerconfigjson is as below (I used Gitlab in this case):

{
"auths": {
"registry.gitlab.com": {
"username": "<username>",
"password": "<password/token>",
"email": "<email>"
}
}
}

5. Create a BuildConfig type binarywhich will use the above secret:

oc new-build --name build-with-docker --binary --strategy docker --to-docker=true --to=<image repository> --push-secret=secret-2-docker

Now our namespace has everything ready.

Connect Jenkins to Openshift

We need to install Kubernetes Plugin for Jenkins before being able to connect to Openshift.

1. Add new Kubernetes configuration for Jenkins
Go to Manage Jenkins -> Manage Nodes and Clouds -> Configure Clouds

Kubernetes URL is the URL of our Openshift. It should be the same value as the one we used for login from the oc login command

For simplicity, we will disable the certificate check in this tutorial.

2. Add Credentials

Click the Add button to add new Credentials

Choose Kind -> Secret text and paste the token we get from the previous section into the Secret field

Now, click the button Test Connection to ensure our Jenkins can connect to Openshift with the provided credential:

3. Add Pod Template

Click Add Pod Template and fill in the required information as below to config the Pod where the Jenkins agent will run later

We also need to specify the service account jenkinsto use for this pod

4. Add Containers

We will use the Maven project in this tutorial, so we need a Maven container inside our Pod.
We will use registry.hub.docker.com/adoptopenjdk/maven-openjdk11 image for the Maven container.

Additionally, we will also need a oc container to trigger build to Openshift. The image that will be used here is registry.hub.docker.com/ebits/openshift-client

Now we are ready to create our Pipeline.

Create Jenkins Pipeline

Let’s have a look at our sample project structure first

This is a pretty simple Maven project. Please be noticed that our Dockerfile is located inside thesample-web folder.

Now, let’s do the below:

  1. Create new Pipeline with name jenkins-openshift-test-pipeline

2. Use the below pipeline script for your build

pipeline {
agent {
kubernetes {
cloud 'openshift-test' #1
inheritFrom 'jenkins-agent' #2
}
}
stages {
stage('Checkout') {
steps {
git 'https://gitlab.com/linhvomedium/cicd/spring-boot-rest-api.git' #3
}
}

stage('Build') {
steps{
container('maven') {
sh "mvn -f sample-web/pom.xml clean install" #4
}
}
}

stage('Publish Image') {
steps{
container('oc') {
sh "oc start-build build-with-docker --from-dir sample-web" #5
}
}
}
}
}

#1: the name of our Cloud Config in the previous step

#2: the name of the pod template within that Cloud Config

#3: check out the target project

#4: run maven command

#5: trigger the Openshift build and point to the sample-web folder where Dockerfile is located

Thus, our build is pretty simple with 3 stages:

  • Checkout: checkout the project from the Git repository
  • Build: build the project inside maven container
  • Publish Image: trigger the Openshift Build, which will also push the resulting image to the Docker registry, inside oc container

Time to build our pipeline

Let’s trigger the newly created Jenkins job

When the build is running, try to list all the pods on the namespace ci-test

oc get pods

We will see a new pod is created with 3 containers:

Let’s get more detail of this pod:

oc describe pod/jenkins-openshift-test-pipeline-10-k9n67-38hpk-1x66w

As the above result, we can see that there are 3 containers running inside the pod:

  • maven and oc: are configurated in our Container template earlier
  • jnlp : is the Jenkins agent container.
    You can change this container spec by specifying a container with the same name in the Container template of our target Cloud Config

When the job completes, we can see one new build has been triggered:

oc get build

Now, a new docker image should have been published to the target Docker Registry:

That’s it!

I'm a software engineer who like writing about things that I have learned