We're very pleased that you want to get in touch with us. Please fill in the form below:



or   Close this form  
Some content

Peter Pilgrim :: Java Champion :: Digital Developer Architect

I design Java EE and Scala software solutions for the blue-chip clients and private sector

Hey all! Thanks for visiting. I provide fringe benefits to interested readers: checkout consultancy, training or mentorship Please make enquiries by email or call +44 (0)7397 067 658.

Due to the Off-Payroll Working plan for the UK government, unfortunately, I am no longer accepting standard GOV.UK contract engagements for the public sector. Please enquire for further information.

Hot shot 008 – Jenkins Pipelines

02 August 2018 Comments off

5 minutes

1123

This are my verbatim notes to the PEAT UK podcast:

 

 

Hello there once again to another hot shot. My name is Peter Pilgrim, platform engineer and DevOps specialist, and Java Champion.

 

 

As DevOps engineer, you probably already heard of Jenkins and continuous integration.

Jenkins was originally an open source project called Hudson, which was created by a former Sun Microsystems engineer: Kohsuke Kawaguchi. He started a hobby project under the name of Hudson, in 2004. It was one of those pet projects that became officially sanctioned and adopted by Kawaguchi’s boss and also his employer.

When Oracle bought Sun Microsystems, and they also took stewardship of the Java brand. It was then that issue with intellectual property rights and inventions of employer’s in 2010, since started to go awry. Oracle claimed right to the name and applied for a trademark. Community in 2011 disagreed with this approach, voted decisively to rename the project Jenkins. Hudson became a fork of Jenkins. In the meantime, Kawaguchi left Oracle and started his business.*

 

 

 

 

Today, Jenkins is the most successfully open source continuous integration in the software developer community. It runs off JVM, it can be launched standalone as JAR, because it embeds Apache Tomcat, when I last checked, which was sometime ago. Jenkins can also be deployed as a WAR file to an Java EE application server such as WildFly, Liberty or Payara.

Because Jenkins has this flexible to launch as a standalone JAR, it was one of the first Uber JAR out there, DevOps people can chuck into a Docker container image.

Jenkins can also to be deployed to AWS EC2 instance, but that is another story.

In this episode, I am going to talk about Jenkins pipelines.

In the field of continuous integration, when we talk about a pipeline, we define a workflow that instructs an engine how to retrieve some code from a remote source code repository, how to build and assemble this code, how to test the assembly and finally delivery it to an environment.

In Jenkins, pipelines are essentially a Groovy DSL (domain specific language). The code looks like a scripting language. A pipeline can be attached one or more Jenkins jobs.

A Jenkins job, therefore, can be standardised.

All your microservices can be build against a standard Jenkins pipeline. For DevOps and Platform engineer we love this feature alot.

There is one single source of truth – infrastructure as code
The pipeline is coded and therefore it is flexible. We can program how it behaves.
It is durable, pausable, versatile and extensible.
Best of all, Jenkins, allows a pipeline to be pulled from a Git repository.

There are two types of pipelines within Jenkins: declarative and scripted pipeline syntax.

Declarative pipelines are suited if your infrastructure targets particular agents. The Declarative DSL limit what you can program with Grocy. You use the pipeline keyword block in the DSL syntax to specify location the entire workflow. An agent might be a particular Docker stage.

Scripted pipelines are build with the node DSL block, which means the workflow is scheduled to a separate Jenkins executor. Scripted pipeline You can think of this a work tasks being pushed one by one onto a queue and then another process executing the task in sequence or in parallel. The Scripted pipeline allow more flexible use of the underlying Groovy programming language, so you use if / then /else and also incorporate try / catch / finally and call more standard Groovy SDK functions.

Whether declarative or scripted pipeline, each workflow is defined into stages. Stage as individually named block that perform some task. You might have three classic stages in your pipeline such “build”, “test” and “deploy”. Both scripted and declarative allow DSL to invoked Shared Libraries.

See the code examples in the accompanying blog article.

This is code for the Declarative Pipeline

pipeline { 
    agent any 
    stages {
        stage('Build') { 
            steps { 
                sh './gradlew clean assemble' 
            }
        }
        stage('Test'){
            steps {
                sh './gradlew test'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh './gradlew deploy'
            }
        }
    }
}

This is code for the Scripted Pipeline

node { 
    stages {
        stage('Build') { 
            steps { 
                sh './gradlew clean assemble' 
            }
        }
        stage('Test'){
            steps {
                sh './gradlew test'
                junit 'reports/**/*.xml' 
            }
        }
        stage('Deploy') {
            steps {
                sh './gradlew deploy'
            }
        }
    }
}

You can also have more stages for code quality. As a DevOps engineer, surely, you would throw in “pmd” or “sonarqube”, “smoke”, “deploy artifact” and “deploy environment” stages.

One nice feature of Jenkins, it is great to put the devops pipeline inside a shared library.

That’s all we have for know. I will stop here. Bye for now.

 

+PP+
July 2018

 

 

Feedback on social media with shares, comments are likes all appreciated. The more the better as they say.

 

 

Here is an advanced example,

import hudson.FilePath;
import jenkins.model.Jenkins;

def call(body) {
    def config = [:]
    body.resolveStrategy = Closure.DELEGATE_FIRST
    body.delegate = config
    body()

    node ('GradleBuild'){
        // Clean workspace before doing anything
        deleteDir()

        stage('Clone') {
            echo "checking out git repo"
            dir('source_dir') {
                checkout scm
            }
        }
        stage('Conditional Debug') {
            if (config.pausePipeline == true) {
                echo "pausing the pipeline (15 minutes) in order to debug the execution inside a Kubernetes pod!"
                dir('source_dir') {
                    sh "sleep 1200"
                }
                echo "Ending pause"
            }
        }
        stage('Build') {
        try {
            dir('source_dir') {
                sh "./gradlew clean assemble"
            }
           }
          catch (exc) {
              echo 'Build Failed.Please check the Jenkins Logs'
              sendFailureNotification()
            }
          }          
        stage ('UnitTests') {
            if (config.includeUnittests == true) {
                try {
                    dir('source_dir') {
                        sh "./gradlew test --stacktrace --info --no-daemon --max-workers 5"
                    }
                }
                catch (exc) {
                    echo 'Test Failed. Please check the Jenkins Logs'
                    sendFailureNotification()
                }
            }
        }
        stage('SonarQube') {
            if (config.includeSonarqube == true) {
              try {
                dir('source_dir') {
                    sh "./gradlew sonarqube"
                }
              }
              catch (exc) {
                  echo 'Sonar Failed. Please check the Jenkins Logs'
                  sendFailureNotification()
                }
            }
        }
        . . .
    }
}

 def sendFailureNotification() {
    emailext (
        replyTo: 'devops-lead@acme.com',
        to: peter.pilgrim@acme.com',
        subject: "FAILED: BUILD Number : ${env.BUILD_NUMBER} - Jenkins Job : ${env.JOB_NAME}",
        body: """<p>FAILED: BUILD Number : ${env.BUILD_NUMBER} - Jenkins Job : ${env.JOB_NAME}</p>
        <p> View Jenkins console output at "<a href="${env.BUILD_URL}">${env.JOB_NAME} [${env.BUILD_NUMBER}]</a>"</p>"""
      )
  }

 

 

References

https://jenkins.io/doc/book/pipeline/

https://jenkins.io/doc/book/pipeline/syntax/

https://jenkins.io/doc/book/pipeline/shared-libraries/

*I although I don’t vocally state in the podcast For the record, I have never taken any side and I am not taking sides in the issue between Oracle and Kawaguchi regarding Hudson vs Jenkins

 

 

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Contents of this blog entry are under copyright © 2017 by Peter Pilgrim and associates. For enquiries after republishing, please contact us for permission. All requests for syndicated content will be ignored /dev/null, consider yourself warned!

I help to design, create and build JVM components and services that are behind popular e-commerce websites.

My Blurb

Please get in touch , directly, to establish hire availability, contract & consulting opportunities.

Speaking at Your Conference

Contact by invitation

What Peter Does

Contact