JavaEE Pipeline as code using Jenkins, Docker and Sonar

Rafael Pestano

Rafael Pestano

Software Engineer at PROCERGS

rsjug logo

See this presentation in PDF here.

Continuous delivery

"A software strategy that enables organizations to deliver new features to users as fast and efficiently as possible"

  • Be ready to delivery in production at any moment!

Why?

"…​ If it hurts, do it more frequently, and bring the pain forward."

— Jez Humble

Goals

  • Reduce the risk of delivering

  • Create a well known delivery process/cycle

  • Make release process painless and without surprises

  • Be ready to go to production at anytime

fear change

Deploy to production

deploy to production

Principles

  • Each commit/push creates a release canditate

    “The longer you delay, the worse(exponentially) the problem becomes“ [Neal Ford - Director at ThoughtWorks]
  • Heavily based on automation

  • Automated tests are primordial

  • Continuous and fast feedback (from end user as well from your release process)

Principles

  • Continuous improvement

  • Colaboration, everyone is responsible for the release process ( DEV, QA, OPs...)

  • Measurable progress
    1. How many builds have failed?

    2. In which stage it failed?

    3. How long it takes to go to production?

Consequences

  • Less severity and frequency of failures related to a release

  • Reduced time to recovery from failures (MTTR)

mttr

Deployment pipeline

"…​ A pipeline is a set of stages to bring funcionality from developers to end users"

continuous deployment pipeline

Jenkins 1.x pipeline

pipeline old

Jenkins 2.x pipeline

declarative announce

Jenkins 2.x pipeline

  • Described in a very easy and powerful DSL

  • Lives on source code (versioning)

  • Reuse with shared libraries

  • Everything in one place (Jenkinsfile)

  • Recovery from restarts

Jenkins 2.x pipeline as code

pipeline {
    agent any

    stages {

        stage('checkout') {

            steps {
                git 'https://github.com/rmpestano/tdc-pipeline.git'
            }
        }

        stage('build') {

            steps {
                sh 'mvn clean package'
            }

        }
    }

}

Jenkins 2.x pipeline on code

pipeline on code

Jenkins 2.x pipeline on code

pipeline {
    agent any

    stages {

     stage('build') {

        steps {
            sh 'mvn clean package'
        }
    }

    stage('Deploy') {
        steps {
            sh 'docker stop tdc-pipeline || true && docker rm tdc-pipeline || true'
            sh 'docker build -t tdc-pipeline .'
            sh 'docker run -d --name tdc-pipeline -p 8181:8080 -v ~/db:/opt/jboss/db tdc-pipeline'
        }
    }
  }
}

Sonar

sonar

Sonar

pipeline {
    agent any

    stages {

         stage('build') {

            steps {
                sh 'mvn clean package -DskipTests'
            }
         }

       stage('unit-tests') {
             steps {
                  sh 'mvn test -Pcoverage'
                }
           }

       stage("SonarQube analysis") {
            steps {
              withSonarQubeEnv('sonar') {
                   sh 'mvn sonar:sonar'
                }
            }
        }

        stage('Deploy') {
            steps {
                sh 'docker stop tdc-pipeline || true && docker rm tdc-pipeline || true'
                sh 'docker build -t tdc-pipeline .'
                sh 'docker run -d --name tdc-pipeline -p 8181:8080 -v ~/db:/opt/jboss/db tdc-pipeline'
            }
        }
  }
}

Quality Gate

you shall not pass

Quality Gate

pipeline {
    agent any

    stages {

     stage('build') {

        steps {
            sh 'mvn clean package -DskipTests'
        }
    }

   stage('unit-tests') {
          steps {
               sh 'mvn test -Pcoverage'
            }
        }

   stage("SonarQube analysis") {
        steps {
          withSonarQubeEnv('sonar') {
               sh 'mvn sonar:sonar'
            }
        }
     }

   stage("Quality Gate") {
        steps {
            sh 'sleep 12s'
            timeout(time: 5, unit: 'MINUTES') {
                script {
                    def result = waitForQualityGate()
                    if (result.status != 'OK') {
                        error "Pipeline aborted due to quality gate failure: ${result.status}"
                        } else {
                            echo "Quality gate passed with result: ${result.status}"
                        }
                    }
                }

            }
   }

    stage('Deploy') {
        steps {
            sh 'docker stop tdc-pipeline || true && docker rm tdc-pipeline || true'
            sh 'docker build -t tdc-pipeline .'
            sh 'docker run -d --name tdc-pipeline -p 8181:8080 -v ~/db:/opt/jboss/db tdc-pipeline'
        }
    }
  }
}

Post actions

pipeline {
    agent any

    //stages

    post {
      always {
            sendNotification(currentBuild.result)
      }

      success {
           echo 'Build was a success'
      }

      failure {
           echo 'Build failure'
      }

      changed {
          echo 'Build status changed.'
      }
   }
}//end pipeline

def sendNotification(buildStatus) {

  buildStatus =  buildStatus ?: 'SUCCESSFUL'

  def color = buildStatus == 'SUCCESSFUL' ? 'good' : 'danger'

  def message = "${currentBuild.fullDisplayName} *${buildStatus}*. (<${env.BUILD_URL}|Open>)"


  slackSend (channel: '#builds', color: color, message: message)

  }

Pipeline shared libraries

Enables reuse of pipeline sections (even entire stages) among projects

TDC Pipeline final

tdc pipeline

Video

Perguntas?

questions

References

thanks