Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Dockerizing Jenkins 2, Part 1: Declarative Build Pipeline With SonarQube Analysis

DZone's Guide to

Dockerizing Jenkins 2, Part 1: Declarative Build Pipeline With SonarQube Analysis

In the first part of this Dockerizing Jenkins series, learn to run Jenkins on Docker, and automate plugin installation, Java and Maven tool configuration, and more.

· DevOps Zone ·
Free Resource

Learn more about how CareerBuilder was able to resolve customer issues 5x faster by using Scalyr, the fastest log management tool on the market. 

This is the first part of the Dockerizing Jenkins series.

In this article, I am going to demonstrate:

  • Running Jenkins on Docker.
  • Automation of Jenkins plugin installation on Docker.
  • Configuring Java and Maven tools on Jenkins, first manually and then via the Groovy scripts.
  • Automating the above step with Docker.
  • Running SonarQube on Docker.
  • Setting up a Java Maven pipeline with unit tests, test coverage, and SonarQube analysis steps.

In the next parts you are also going to learn:

Part 2: Deployment With Maven and JFrog

  • Running JFrog Artifactory on Docker.
  • Configuring the Maven pom file.
  • Configuring the Maven settings file.
  • Using Config File Provider Plugin for persistence of Maven settings.
  • Dockerizing the installation and configuration process.

Part 3: Securing Passwords With docker-compose, docker-secret and Jenkins Credentials Plugin

  • How to use docker-compose to run containers.
  • How to use passwords in docker environment with docker-secrets.
  • How to hide sensitive information in Jenkins with credentials plugin.

Part 4: Putting Jenkins Build Logs Into Dockerized ELK Stack

  • Configure and run Logstash in a Docker container.
  • Configure and run Elasticsearch in a Docker container.
  • Configure and run Kibana in a Docker container.
  • Run Jenkins with preinstalled Filebeat to send the logs into ELK.

Image titleThis is a practical example, so be ready to get your hands dirty. You can either follow this step by step guide, which would be really good for learning purposes as we will create everything from scratch, or if you are lazy, just run the command below after reading for the demo:

git clone https://github.com/kenych/jenkins_docker_pipeline_tutorial1 && cd jenkins_docker_pipeline_tutorial1 && ./runall.sh

By the end, you should be able to run the pipeline on a fully automated Jenkins Docker container.

Please note, some of the code in the article won't work as it is in the future, things like jenkins base image and list of plugins, URI for downloading maven and java will change and might break the code, but the code provided in the git repo should work as I keep updating it based on reviewers comments.

As you may already know, with Jenkins 2, you can actually have your build pipeline right within your Java project, so you can actually use your own Maven Java project in order to follow the steps in this article as long as it is hosted on a Git repository.

Everything obviously will be running on Docker, as it is the easiest way of deploying and running them.

So, let’s see how to run Jenkins on Docker:

docker pull jenkins:2.60.1

While it is downloading in the background, let’s see what we are going to do with it once it is done.

Default Jenkins comes quite naked and shows a suggested plugins installation wizard. We will choose it, then we will capture all installed plugins and then automate this manual step in a Docker image and will follow this simple rule throughout all the steps:

  1. Set up manually.
  2. Set up programmatically.
  3. Automate with Docker.

The image we are going to download is 600M so you can prepare yourself a coffee and a have couple sips before it is finished and I will take you through the steps we need to setup up build a pipeline for a Java project. Let’s add them to the list and then look closer later:

  • Pull the code from scm.
  • Configuration of Java and Maven.
  • Running unit tests.
  • Running static analysis.
  • Sending report to SonarQube for further processing.
  • And finally, deployment of the .jar file to the repository (will be covered in the next part soon).
  • Optionally, we can also release it after each commit.

Once you have your image downloaded, let’s run the container:

docker run -p 8080:8080 --rm --name myjenkins jenkins:2.60.1

Please note that I used a specific tag; I am not using the latest tag, which is the default if you don’t specify one, as I don’t want anything to break in the future.

Also note that we name the container so it is easier to refer to it later, as otherwise, Docker will name it randomly, and we added the –-rm flag to delete the container once we stop it; this will ensure we are running Jenkins in an immutable fashion and everything configures on the fly, and if we want to preserve any data, we will do it explicitly.

If you get an error that port 8080 is busy, just choose the one which is free for the first part of 8080:8080. The first one is the host port and the second one is the port where Jenkins will run inside the container. Let’s open localhost:8080 (or whatever you have chosen as the host port). You should see the screenshot below for putting in an admin password:

Image titleGrab it from from the Docker logs and paste it there:

Image titleYou should be seeing a plugin installation wizard now:

Image titleChoose the suggested plugins option and Jenkins will start the installation of plugins. Once this is done, we need to capture the plugins installed and then automate them in Docker.

Open http://localhost:8080/script and paste this Groovy script and run it:

Jenkins.instance.pluginManager.plugins.each{
  plugin ->
    println ("${plugin.getShortName()}")
}

Image title

Now, copy plugins that are displayed in the list- that is, all text from the top, up to the “Result:” section and create a file plugins.txt and paste the copied text there.

There are two alternative ways of getting the installed plugins:

Thanks to this method

curl "http://192.168.1.7:8080/pluginManager/api/json?depth=1" | jq -r '.plugins[].shortName'

Or an even more extreme way which I came up with, from the container:

docker exec -it myjenkins ls /var/jenkins_home/plugins/ | grep -v jpi

You can also use CLI; first, download it from http://localhost:8080/jnlpJars/jenkins-cli.jar, then run:

java -jar jenkins-cli.jar -s http://localhost:8080/ list-plugins

I have deliberately chosen the Groovy script version as you will need this script running window thing quite a lot to test different scripts that we will use to configure Jenkins programmatically.

Let’s stop the container and automate this step:

docker stop myjenkins

Or simply press CTRL + C.

Let’s start Dockerizing the Jenkins plugin installation part now by creating an empty file called Dockerfile and adding couple lines to it:

#this is the base image we use to create our image from
FROM jenkins:2.60.1

#just info about who created this
MAINTAINER Kayan Azimov (email)

#get rid of admin password setup
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"

#automatically installing all plugins
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

Please make sure you have an empty new line in the end of plugins.txt file, as otherwise, Jenkins will complain during the installation of the plugins. Time to build our image:

docker build -t myjenkins .

Pay attention to the dot in the end, don’t miss it. It is going to take a while as now the Jenkins image has instructions to download and install the plugins we defined in plugins.txt. Once it is ready, we can run it:

docker run -p 8080:8080 --rm --name myjenkins myjenkins:latest

Please note that this time we are running the container not from the default image, but the one we have just baked. You can check installed plugins by running the same script we did or just in the UI:

Image title

Tool Installation

So far it is good and the first stage is completed. Now it's time for Java and Maven tool installation. Jenkins has the ability to configure any tool on the fly when it is required. It is sort of like old style Docker. Given that Jenkins was designed a decade ago, this is actually quite a cool feature, but I think in the future it won’t be continued as more and more tools are becoming available as Docker containers. You can read more about tool here.

Let’s start with Java. Even though we are actually running Jenkins on Java, meaning we must have Java installed, we aren’t going to use it. Instead we should be able to run our project with any version of Java. But first, we need to have all the tools needed in hand. Let’s download a couple versions of Java. I found a place where you can find any versions of JDK; if it doesn’t work, you can Google it.

curl -O http://ftp.osuosl.org/pub/funtoo/distfiles/oracle-java/jdk-8u131-linux-x64.tar.gz
curl -O http://ftp.osuosl.org/pub/funtoo/distfiles/oracle-java/jdk-7u76-linux-x64.tar.gz

And then download Maven:

curl -O http://apache.mirror.anlx.net/maven/maven-3/3.5.0/binaries/apache-maven-3.5.0-bin.tar.gz

Create a downloads folder and copy them there. Your downloads directory should look like this now:

➜ my_jenkins tree downloads
downloads
├── apache-maven-3.5.0-bin.tar.gz
├── jdk-7u76-linux-x64.tar.gz
└── jdk-8u131-linux-x64.tar.gz

0 directories, 3 files
➜ my_jenkins

Once done, we are ready to run the container again. This time I mounted a host directory “downloads” as a volume inside of the container, so it can access the files in the host folder in order to download Maven and Java later:

docker run -p 8080:8080 -v `pwd`/downloads:/var/jenkins_home/downloads --rm --name myjenkins myjenkins:latest

Let’s make sure we can see the contents of the folder from within the container:

➜  ~ docker exec -it myjenkins ls -l /var/jenkins_home/downloads

total 328444
-rw-r--r-- 1 jenkins jenkins   8534562 Jul  4 22:29 apache-maven-3.5.0-bin.tar.gz
-rw-r--r-- 1 jenkins jenkins 142249690 Jul  4 23:08 jdk-7u76-linux-x64.tar.gz
-rw-r--r-- 1 jenkins jenkins 185540433 Jul  4 21:35 jdk-8u131-linux-x64.tar.gz
➜  ~

We are now ready to install the tools, so go to the URL http://localhost:8080/configureTools/ by choosing Manage Jenkins -> Global Tool Configuration.

In the JDK section, delete the Oracle Installer, we won’t use that. It requires an Oracle account (why on earth do you need an account to download bloody Java!).

Image title

Image title

You need to specify the name, URL, and folder name. Setup as in the screenshot, the URL will be used to download the binary and folder to refer to the unzipped package, so having them correctly set up is crucial. Let’s setup Java 7 and 8 as well.

Image title

Then Maven:

Image title

Now we can check if our tools are configured correctly inside Jenkins. Let’s create a job and set up its type to the pipeline and start writing our code:

Image title

pipeline {
    agent any
    tools {
        jdk 'jdk7'
        maven 'maven3'
    }
    stages {
        stage('test java installation') {
            steps {
                sh 'java -version'
                sh 'which java'
            }
        }
        stage('test maven installation') {
            steps {
                sh 'mvn -version'
                sh 'which mvn'
            }
        }
    }
}

It was a tedious process, wasn’t it, the tool installation. Imagine if you had dozens of tools in Jenkins, that is how normal Jenkins will look like in any real production system:

  • A couple versions of Java,
  • A couple versions of NodeJS,
  • Maven,
  • Sonar, to name a few.

But once we automate this process, we can just run it and relax. Now that you have everything hopefully working, it is time to automate tool installation. You can delete the tools you have added and recreate them via the script.

Go to the script section and copy and run these scripts one by one, which installs everything we did earlier programmatically:

import hudson.model.JDK
import hudson.tools.InstallSourceProperty
import hudson.tools.ZipExtractionInstaller

def descriptor = new JDK.DescriptorImpl();


def List<JDK> installations = []

javaTools=[['name':'jdk8', 'url':'file:/var/jenkins_home/downloads/jdk-8u131-linux-x64.tar.gz', 'subdir':'jdk1.8.0_131'],
      ['name':'jdk7', 'url':'file:/var/jenkins_home/downloads/jdk-7u76-linux-x64.tar.gz', 'subdir':'jdk1.7.0_76']]

javaTools.each { javaTool ->

    println("Setting up tool: ${javaTool.name}")

    def installer = new ZipExtractionInstaller(javaTool.label as String, javaTool.url as String, javaTool.subdir as String);
    def jdk = new JDK(javaTool.name as String, null, [new InstallSourceProperty([installer])])
    installations.add(jdk)

}
descriptor.setInstallations(installations.toArray(new JDK[installations.size()]))
descriptor.save()

And Maven:

import hudson.tasks.Maven
import hudson.tasks.Maven.MavenInstallation;
import hudson.tools.InstallSourceProperty;
import hudson.tools.ToolProperty;
import hudson.tools.ToolPropertyDescriptor
import hudson.tools.ZipExtractionInstaller;
import hudson.util.DescribableList
import jenkins.model.Jenkins;

def extensions = Jenkins.instance.getExtensionList(Maven.DescriptorImpl.class)[0]

List<MavenInstallation> installations = []

mavenToool = ['name': 'maven3', 'url': 'file:/var/jenkins_home/downloads/apache-maven-3.5.0-bin.tar.gz', 'subdir': 'apache-maven-3.5.0']

println("Setting up tool: ${mavenToool.name} ")

def describableList = new DescribableList<ToolProperty<?>, ToolPropertyDescriptor>()
def installer = new ZipExtractionInstaller(mavenToool.label as String, mavenToool.url as String, mavenToool.subdir as String);

describableList.add(new InstallSourceProperty([installer]))

installations.add(new MavenInstallation(mavenToool.name as String, "", describableList))

extensions.setInstallations(installations.toArray(new MavenInstallation[installations.size()]))
extensions.save()

Check the tools; everything we created earlier is there again. Yay!

Let’s test it and make sure it is actually working by creating and running same test pipeline. Oh, snap! It is gone of course, as we delete the container when we stop it.

So let’s make sure next time we destroy the container, jobs aren’t lost. Stop the container, again, create directory jobs in the current directory, and run it with the next command:

docker run -p 8080:8080  -v `pwd`/downloads:/var/jenkins_home/downloads -v `pwd`/jobs:/var/jenkins_home/jobs/ --rm --name myjenkins myjenkins:latest

Now we are saving all jobs in the jobs directory on the host, so next time you destroy the container, it will be there when we run it again.

Let’s Dockerize the automation now. Create Groovy files and put them in the Groovy folder in the project.

Image title

Your Dockerfile should look like below:

#this is the base image we use to create our image from
FROM jenkins:2.60.1

#just info about who created this
MAINTAINER Kayan Azimov (email)

#get rid of admin password setup
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"

#automatically installing all plugins
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt

#adding scripts
COPY groovy/* /usr/share/jenkins/ref/init.groovy.d/

We did this because when Jenkins starts, it runs all scripts in a directory called init.groovy.

We are now ready to build a new image and run it:

➜  my_jenkins   docker build -t myjenkins .

Sending build context to Docker daemon  336.7MB
Step 1/6 : FROM jenkins:2.60.1
 ---> 0b4d4d677a26
Step 2/6 : MAINTAINER Kayan Azimov
 ---> Using cache
 ---> 67b933684219
Step 3/6 : ENV JAVA_OPTS "-Djenkins.install.runSetupWizard=false"
 ---> Using cache
 ---> 058a419179cb
Step 4/6 : COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
 ---> Using cache
 ---> 98b3e9b27bdc
Step 5/6 : RUN /usr/local/bin/install-plugins.sh < /usr/share/jenkins/ref/plugins.txt ---> Using cache
 ---> 1d10702cc94a
Step 6/6 : COPY groovy/* /usr/share/jenkins/ref/init.groovy.d/
 ---> c81d7db388c9
Removing intermediate container 83ee1aa76a22
Successfully built c81d7db388c9
Successfully tagged myjenkins:latest
➜  my_jenkins

And then run the container:

➜  my_jenkins docker run -p 8080:8080  -v `pwd`/downloads:/var/jenkins_home/downloads -v `pwd`/jobs:/var/jenkins_home/jobs/ --rm --name myjenkins myjenkins:latest

You should see installation happening in the logs:

Jul 05, 2017 8:27:50 PM jenkins.util.groovy.GroovyHookScript execute
INFO: Executing /var/jenkins_home/init.groovy.d/java.groovy
Jul 05, 2017 8:27:50 PM hudson.model.AsyncPeriodicWork$1 run
INFO: Started Download metadata
Setting up tool: jdk8
Setting up tool: jdk7
Jul 05, 2017 8:27:50 PM jenkins.util.groovy.GroovyHookScript execute
INFO: Executing /var/jenkins_home/init.groovy.d/maven.groovy
Setting up tool: maven3
Jul 05, 2017 8:27:51 PM jenkins.util.groovy.GroovyHookScript execute
INFO: Executing /var/jenkins_home/init.groovy.d/tcp-slave-agent-port.g

Check the test pipeline (it should be there this time), and run it.

If all is good and our test pipeline is working, it is time to create a pipeline for our Java Maven project.

Create a new pipeline job, but this time, select Pipeline script from SCM and specify the path to your Git Maven project.

Image title

If you don’t have one, you can use the one in this example, or if you don’t want to commit changes every time we test the pipeline, you can always update it right in Jenkins instead of pushing a new Jenkins file, by just clicking the arrow next to the last job and selecting Replay and updating the script:

Image title

Otherwise, create a file called Jenkins in your Git projectwith the content as below, push your changes, and run the build:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('Install') {
            steps {
                sh "mvn clean test"
            }
        }
    }
}

You just have run first step successfully. Great, let’s move forward and publish test results:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('Install') {
            steps {
                sh "mvn clean test"
            }
            post {
                always {
                    junit '**/target/*-reports/TEST-*.xml'
                }
            }
        }
    }
}

Image title

And now add test coverage with the Maven Cobertura plugin:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('Install') {
            steps {
                sh "mvn -U clean test cobertura:cobertura -Dcobertura.report.format=xml"
            }
            post {
                always {
                    junit '**/target/*-reports/TEST-*.xml'
                }
            }
        }
    }
}

In the job logs, you should see this now:

at net.sourceforge.cobertura.reporting.xml.XMLReportFormatStrategy.save(XMLReportFormatStrategy.java:18)
    at net.sourceforge.cobertura.reporting.NativeReport.export(NativeReport.java:31)
    at net.sourceforge.cobertura.reporting.CompositeReport.export(CompositeReport.java:19)
    at net.sourceforge.cobertura.reporting.ReportMain.parseArgumentsAndReport(ReportMain.java:91)
    at net.sourceforge.cobertura.reporting.ReportMain.generateReport(ReportMain.java:141)
    at net.sourceforge.cobertura.reporting.ReportMain.main(ReportMain.java:151)

[INFO] Cobertura Report generation was successful.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

If you check the build logs, ignore some Cobertura issues if running a Java 8 project, as Cobertura doesn’t support Java 8; I will probably update it to use Jacoco in the next session.

In order to see Cobertura results on Jenkins page you need the plugin, let’s first install manually by going to http://localhost:8080/pluginManager/advanced.

Then download the HPI file from http://updates.jenkins-ci.org/latest/cobertura.hpi and click on "upload plugin."

You can now stop the container, add Cobertura to the list in the plugins.txt, and rebuild the image, but don’t run it yet!

The point is, there is something else which could make our builds faster after the container is destroyed. If you have noticed, every time we destroy the container and run it again after a new image is built, the job takes ages for the very first time and you can see these logs:

Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-compiler-plugin/3.1/maven-compiler-plugin-3.1.pom (10 kB at 16 kB/s)


Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/24/maven-plugins-24.pom
Progress (1): 2.1/11 kB
Progress (1): 4.9/11 kB
Progress (1): 7.7/11 kB
Progress (1): 10/11 kB 
Progress (1): 11 kB   

Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-plugins/24/maven-plugins-24.pom (11 kB at 68 kB/s)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-parent/23/maven-parent-23.pom
Progress (1): 2.1/33 kB
Progress (1): 4.9/33 kB
Progress (1): 7.7/33 kB
Progress (1): 10/33 kB 
Progress (1): 13/33 kB
Progress (1): 16/33 kB
Progress (1): 19/33 kB
Progress (1): 21/33 kB
Progress (1): 24/33 kB
Progress (1): 27/33 kB
Progress (1): 30/33 kB
Progress (1): 32/33 kB
Progress (1): 33 kB 

That is because Maven resolves project dependencies and saves them to var/jenkins_home/.m2/repository and if you run the job again, it won’t download them again. The thing is, it is lost when the container is destroyed. So let’s add them via volume just like we did for jobs. To do so, just run the container with the below command:

mkdir m2deps
docker run -p 8080:8080  -v `pwd`/downloads:/var/jenkins_home/downloads -v `pwd`/jobs:/var/jenkins_home/jobs/ -v `pwd`/m2deps:/var/jenkins_home/.m2/repository/ --rm --name myjenkins myjenkins:latest

The container is now downloading the Cobertura plugin:

Image title

Ignore this error in the logs; despite this exception, the plugin still works, just some unresolved Jira issue. We can now add the Cobertura publisher to the pipeline:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('Install') {
            steps {
                sh "mvn -U clean test cobertura:cobertura -Dcobertura.report.format=xml"
            }
            post {
                always {
                    junit '**/target/*-reports/TEST-*.xml'
                    step([$class: 'CoberturaPublisher', coberturaReportFile: 'target/site/cobertura/coverage.xml'])
                }
            }
        }
    }
}

If you run the job now, you should get these nice reports:

Image title

Now it's time for a SonarQube analysis. We are going to use the Maven Sonar plugin. I am not going to explain here what SonarQube is, but in short, it keeps the track of code quality issues; you can read about it here.

Pull and then run the container:

docker pull sonarqube

Another big image, around 700M, so time for a break...and once it's done, run it:

docker run  -p 9000:9000 --rm --name mysonar sonarqube

Open http://localhost:9000 and login as admin:admin and check what is there if you are curious, otherwise, stop your Jenkins container and run it again with the Sonar host. You will need to use the host’s IP address and not localhost as that will point to the Docker container’s localhost. The easiest way to find your IP (on Mac):

~ ifconfig | grep "inet " | grep -v 127.0.0.1

    inet 192.168.1.7 netmask 0xffffff00 broadcast 192.168.1.255
➜  ~

Now run the Jenkins container with the environment variable set:

docker run -p 8080:8080  -v `pwd`/downloads:/var/jenkins_home/downloads -v `pwd`/jobs:/var/jenkins_home/jobs/ -v `pwd`/m2deps:/var/jenkins_home/.m2/repository/ --rm --name myjenkins -e SONARQUBE_HOST=http://192.168.1.7:9000 myjenkins:latest

Once Jenkins is up, update the pipeline with Sonar stage:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('Install') {
            steps {
                sh "mvn -U clean test cobertura:cobertura -Dcobertura.report.format=xml"
            }
            post {
                always {
                    junit '**/target/*-reports/TEST-*.xml'
                    step([$class: 'CoberturaPublisher', coberturaReportFile: 'target/site/cobertura/coverage.xml'])
                }
            }
        }
        stage('Sonar') {
            steps {
                sh "mvn sonar:sonar -Dsonar.host.url=${env.SONARQUBE_HOST}"
            }
        }

    }
}

The job logs will look like this:

[INFO] Sensor CPD Block Indexer (done) | time=82ms
[INFO] SCM provider for this project is: git
[INFO] 33 files to be analyzed


[INFO] 33/33 files analyzed
[INFO] Calculating CPD for 4 files
[INFO] CPD calculation finished


[INFO] Analysis report generated in 1781ms, dir size=88 KB


[INFO] Analysis reports compressed in 8120ms, zip size=72 KB


[INFO] Analysis report uploaded in 794ms
[INFO] ANALYSIS SUCCESSFUL, you can browse http://192.168.1.7:9000/dashboard/index/ken:berlin-clock
[INFO] Note that you will be able to access the updated dashboard once the server has processed the submitted analysis report
[INFO] More about the report processing at http://192.168.1.7:9000/api/ce/task?id=AV0Zqa6f3jKwEhMXqqnG
[INFO] Task total time: 26.487 s
[INFO] ------------------------------------------------------------------------

Once you run it, let's go and check the report on the SonarQube side.

OMG! My code has 23 code smells. If you fix one of the smelly issues and rerun the job, check the report; you should see Sonar will detect the fix with the committer information.

Image title

Finally, our pipeline is ready:

Image titleWe can make a subtle improvement here. SonarQube uses source code only, meaning we can run Maven install and Sonar in parallel stages. Unfortunately, this is not yet implemented, but should be resolved in this story, but we can still use parallel steps:

pipeline {
    agent any

    tools {
        jdk 'jdk8'
        maven 'maven3'
    }

    stages {
        stage('install and sonar parallel') {
            steps {
                parallel(install: {
                    sh "mvn -U clean test cobertura:cobertura -Dcobertura.report.format=xml"
                }, sonar: {
                    sh "mvn sonar:sonar -Dsonar.host.url=${env.SONARQUBE_HOST}"
                })
            }
            post {
                always {
                    junit '**/target/*-reports/TEST-*.xml'
                    step([$class: 'CoberturaPublisher', coberturaReportFile: 'target/site/cobertura/coverage.xml'])
                }
            }
        }
    }
}

That is it, you now have a fully automated Jenkins Docker image for this build pipeline with some important stages. Next time, I am going to show how to deploy a Maven project to the artifact repository and that will involve some interesting steps including a couple Jenkins plugins and automation of plugin configuration as well.

Finally, if you were too lazy to follow the steps, you can just run the command below; it doesn’t require any setup apart from having Docker installed. I hope you found this article useful, and if you did, follow updates from me as the deployment part is more interesting!

git clone https://github.com/kenych/jenkins_docker_pipeline_tutorial1 && cd jenkins_docker_pipeline_tutorial1 && ./runall.sh

Find out more about how Scalyr built a proprietary database that does not use text indexing for their log management tool.

Topics:
docker ,jenkins ,sonarqube ,pipeline as code ,jenkins ci ,artifactory ,parallel build

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}