Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Creating a CI/CD Pipeline for Your Shared Libraries

Creating a CI/CD Pipeline for Your Shared Libraries

At Capital One we run tens of thousands of CI/CD pipelines on Jenkins, leveraging the Jenkins Pipeline shared libraries extension to enable code reuse and reduce time to market for dev teams. A code change to our shared library goes live immediately and is consumed the next time a team triggers their project's pipeline. So, why do we have such confidence that a code change to our library won't break a team's pipeline? The answer: we've developed an automated CI/CD pipeline for our shared library.

During this talk, you will learn how to create an automated pipeline for your shared libraries including how to develop tests, create canary releases, monitor for issues, and quickly rollback changes to achieve rapid delivery while minimizing the impact on dev teams.

2d9c7a8cdab3ace496e6d4c68ac7ef1c?s=128

Roderick Randolph

August 14, 2019
Tweet

Transcript

  1. Creating a CI/CD Pipeline for Your Shared Libraries Roderick R.

    Randolph
  2. © 2019 All Rights Reserved. 2

  3. © 2019 All Rights Reserved. 3 https://jenkins.io/doc/book/pipeline-as-code/

  4. © 2019 All Rights Reserved. 4 // Jenkinsfile stage('Build') {

    node('docker') { sh "docker build -t <registry>/my-repo/my-app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my-repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my-app:${version}" } } } } * Source code shown is simulated for demo purposes only
  5. © 2019 All Rights Reserved. 5

  6. © 2019 All Rights Reserved. 6 // Jenkinsfile stage('Build') {

    node('docker') { sh "docker build -t <registry>/my-repo/my-new-app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my-repo/my-new-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my-new-app:${version}" } } } } * Source code shown is simulated for demo purposes only
  7. © 2019 All Rights Reserved. 7 // Jenkinsfile stage('Build') {

    node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } Project A Project B Project C * Source code shown is simulated for demo purposes only
  8. © 2019 All Rights Reserved. 8

  9. © 2019 All Rights Reserved. 9 // Jenkinsfile stage('Build') {

    node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg http_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg http_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } Project A Project B Project C * Source code shown is simulated for demo purposes only
  10. © 2019 All Rights Reserved. 10

  11. © 2019 All Rights Reserved. 11

  12. © 2019 All Rights Reserved. 12 // Jenkinsfile stage('Build') {

    node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } // Jenkinsfile stage('Build') { node('docker') { sh "docker build -t <registry>/my-repo/my- app:${version} --build-arg https_proxy=http://<proxy>:8080 ." def imageId = sh( script: "docker inspect <registry>/my- repo/my-app:${version} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) withCredentials([usernamePassword(...)]) { retry(3) { sh "docker push <registry>/my-repo/my- app:${version}" } } } } * Source code shown is simulated for demo purposes only
  13. © 2019 All Rights Reserved. 13

  14. © 2019 All Rights Reserved. 14 DRY!

  15. © 2019 All Rights Reserved. 15 https://wiki.jenkins.io/display/JENKINS/Pipeline+Shared+Groovy+Libraries+Plugin

  16. © 2019 All Rights Reserved. 16 ➜ ~ git init

    shared-libraries Initialized empty Git repository in shared-libraries/.git/ ➜ ~ cd shared-libraries ➜ shared-libraries git:(master) mkdir vars ➜ shared-libraries git:(master) vi vars/dockerBuild.groovy Creating A Shared Libraries Repository
  17. © 2019 All Rights Reserved. 17 // vars/dockerBuild.groovy def call(Map

    params) { def registry = "<registry>" def image = params.image def proxy = params.withProxy ? '--build-arg https_proxy=http://<proxy>:8080' : '' node('docker') { sh "docker build -t ${registry}/${image} ${proxy} ." if (params.withScan) { def imageId = sh( script: "docker inspect ${registry}/${image} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) } if (params.pushToRegistry) { withCredentials([usernamePassword(credentialsId: params.credentialsId)]) { retry(3) { sh "docker push ${registry}/${image}" } } } } } * Source code shown is simulated for demo purposes only
  18. © 2019 All Rights Reserved. 18

  19. © 2019 All Rights Reserved. 19 // Jenkinsfile library('shared-libraries') stage('Build')

    { dockerBuild( image: "my-repo/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } * Source code shown is simulated for demo purposes only
  20. © 2019 All Rights Reserved. 20 // Jenkinsfile library('shared-libraries') stage('Build')

    { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } // Jenkinsfile library('shared-libraries') stage('Build') { dockerBuild( image: "my-namespace/my-app:${version}", withProxy: true, withScan: true, credentialsId: "...", pushToRegistry: true, ) } * Source code shown is simulated for demo purposes only
  21. © 2019 All Rights Reserved. 21

  22. © 2019 All Rights Reserved. 22

  23. © 2019 All Rights Reserved. 23

  24. © 2019 All Rights Reserved. 24

  25. © 2019 All Rights Reserved. 25 Shared Jenkins Pipeline Library

  26. © 2019 All Rights Reserved. 26 Shared Jenkins Pipeline Library

    https://www.cloudbees.com/blog/ensuring-corporate-standards-pipelines-custom-marker-files
  27. © 2019 All Rights Reserved. 27 Shared Jenkins Pipeline Library

    https://www.cloudbees.com/blog/ensuring-corporate-standards-pipelines-custom-marker-files
  28. © 2019 All Rights Reserved. 28 Shared Jenkins Pipeline Library

    def libVersion = getLibraryVersion() echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline * Source code shown is simulated for demo purposes only the bootstrap script
  29. © 2019 All Rights Reserved. 29 def libVersion = getLibraryVersion()

    echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline Shared Jenkins Pipeline Library * Source code shown is simulated for demo purposes only
  30. © 2019 All Rights Reserved. 30 def libVersion = getLibraryVersion()

    echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline Shared Jenkins Pipeline Library * Source code shown is simulated for demo purposes only
  31. © 2019 All Rights Reserved. 31 def libVersion = getLibraryVersion()

    echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline Shared Jenkins Pipeline Library * Source code shown is simulated for demo purposes only this is the developer's Jenkinsfile
  32. © 2019 All Rights Reserved. 32 def libVersion = getLibraryVersion()

    echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline Shared Jenkins Pipeline Library * Source code shown is simulated for demo purposes only
  33. © 2019 All Rights Reserved. 33 TO PIN, OR NOT

    TO PIN, that is the question
  34. © 2019 All Rights Reserved. 34 Benefits of Latest... •

    Bugs and other major issues are resolved quicker • New features and capabilities are available for immediate use • Reduces the painful software upgrade "headaches"
  35. © 2019 All Rights Reserved. 35 Shared Jenkins Pipeline Library

    Daily Releases
  36. © 2019 All Rights Reserved. 36 Shared Library Guiding Principles

    Keep changes small & digestible Always maintain backwards compatibility Design clean API interfaces
  37. © 2019 All Rights Reserved. 37 // Jenkinsfile library('shared-libraries') stage('Build')

    { dockerBuild( image: "my-repo/my-app:${version}", pushToRegistry: true, ) } * Source code shown is simulated for demo purposes only
  38. © 2019 All Rights Reserved. 38 // Jenkinsfile library('shared-libraries') stage('Build')

    { dockerBuild( image: "my-repo/my-app:${version}", pushToRegistry: true, withArtifactoryRegistry: true, ) } * Source code shown is simulated for demo purposes only
  39. © 2019 All Rights Reserved. 39 Shared Library Branching Strategy

    master v0.1.0 Merge the PR Run the Jenkins pipeline Create release Address PR feedback Open a Pull Request Run the Jenkins pipeline Add some commits
  40. © 2019 All Rights Reserved. 40 Build Test Release Rollback

    Checkpoint End Start The CI/CD Pipeline
  41. © 2019 All Rights Reserved. 41 The CI/CD Pipeline Build

    Test Release Rollback Checkpoint End Start
  42. © 2019 All Rights Reserved. 42 The CI/CD Pipeline -

    Build // build.gradle plugins { id 'groovy' id 'jacoco' id 'codenarc' } sourceSets { main { groovy { srcDirs = ['src'] } resources { srcDirs = ['resources'] } } } dependencies { testCompile(group: 'com.lesfurets', name: 'jenkins-pipeline-unit', version: '1.0') testCompile(group: 'junit', name: 'junit', version: '4.12') testCompile(group: 'org.assertj', name: 'assertj-core', version: '3.13.2') } * Source code shown is simulated for demo purposes only
  43. © 2019 All Rights Reserved. 43 The CI/CD Pipeline -

    Build // Jenkinsfile stage('Build') { steps { sh './gradlew assemble' } } * Source code shown is simulated for demo purposes only
  44. © 2019 All Rights Reserved. 44 The CI/CD Pipeline Build

    Test Release Rollback Checkpoint End Start
  45. © 2019 All Rights Reserved. 45 // vars/dockerBuild.groovy def call(Map

    params) { def registry = "<registry>" def image = params.image def proxy = params.withProxy ? '--build-arg https_proxy=http://<proxy>:8080' : '' node('docker') { sh "docker build -t ${registry}/${image} ${proxy} ." if (params.withScan) { def imageId = sh( script: "docker inspect ${registry}/${image} -f '{{.ID}}'", returnStdout: true, ) scanImageForVulns(imageId: imageId) } if (params.pushToRegistry) { withCredentials([usernamePassword(credentialsId: params.credentialsId)]) { retry(3) { sh "docker push ${registry}/${image}" } } } } } * Source code shown is simulated for demo purposes only
  46. © 2019 All Rights Reserved. 46 The CI/CD Pipeline -

    Test https://github.com/jenkinsci/JenkinsPipelineUnit
  47. © 2019 All Rights Reserved. 47 // src/test/jenkinsfiles/dockerBuild/Jenkinsfile #!groovy stage('Build')

    { dockerBuild( image: 'my-namespace/my-app:0.1.0', pushToRegistry: true, ) } The CI/CD Pipeline - Test * Source code shown is simulated for demo purposes only this is a mocked Jenkinsfile
  48. © 2019 All Rights Reserved. 48 // src/test/jenkinsfiles/dockerBuild/Jenkinsfile #!groovy stage('Build')

    { dockerBuild( image: 'my-namespace/my-app:0.1.0', pushToRegistry: true, ) } The CI/CD Pipeline - Test * Source code shown is simulated for demo purposes only
  49. © 2019 All Rights Reserved. 49 // src/test/groovy/DockerBuildTest.groovy import static

    com.lesfurets.jenkins.unit.MethodCall.callArgsToString import static org.assertj.core.api.Assertions.assertThat import com.lesfurets.jenkins.unit.BasePipelineTest import org.junit.Test public class DockerBuildTest extends BasePipelineTest { // ... @Test void shouldPushToRegistry() { loadScript('dockerBuild/Jenkinsfile') printCallStack() assertThat(helper.callStack.findAll { call -> call.methodName == 'sh' }.any { call -> callArgsToString(call).contains('docker push <registry>/my-repo/my-app:0.1.0') }).isTrue() assertJobStatusSuccess() } } * Source code shown is simulated for demo purposes only
  50. © 2019 All Rights Reserved. 50 // src/test/groovy/DockerBuildTest.groovy import static

    com.lesfurets.jenkins.unit.MethodCall.callArgsToString import static org.assertj.core.api.Assertions.assertThat import com.lesfurets.jenkins.unit.BasePipelineTest import org.junit.Test public class DockerBuildTest extends BasePipelineTest { // ... @Test void shouldPushToRegistry() { loadScript('dockerBuild/Jenkinsfile') printCallStack() assertThat(helper.callStack.findAll { call -> call.methodName == 'sh' }.any { call -> callArgsToString(call).contains('docker push <registry>/my-repo/my-app:0.1.0') }).isTrue() assertJobStatusSuccess() } } * Source code shown is simulated for demo purposes only loads our mocked Jenkinsfile
  51. © 2019 All Rights Reserved. 51 // src/test/groovy/DockerBuildTest.groovy import static

    com.lesfurets.jenkins.unit.MethodCall.callArgsToString import static org.assertj.core.api.Assertions.assertThat import com.lesfurets.jenkins.unit.BasePipelineTest import org.junit.Test public class DockerBuildTest extends BasePipelineTest { // ... @Test void shouldPushToRegistry() { loadScript('dockerBuild/Jenkinsfile') printCallStack() assertThat(helper.callStack.findAll { call -> call.methodName == 'sh' }.any { call -> callArgsToString(call).contains('docker push <registry>/my-repo/my-app:0.1.0') }).isTrue() assertJobStatusSuccess() } } * Source code shown is simulated for demo purposes only prints the call stack to make troubleshooting easier
  52. © 2019 All Rights Reserved. 52 // src/test/groovy/DockerBuildTest.groovy import static

    com.lesfurets.jenkins.unit.MethodCall.callArgsToString import static org.assertj.core.api.Assertions.assertThat import com.lesfurets.jenkins.unit.BasePipelineTest import org.junit.Test public class DockerBuildTest extends BasePipelineTest { // ... @Test void shouldPushToRegistry() { loadScript('dockerBuild/Jenkinsfile') printCallStack() assertThat(helper.callStack.findAll { call -> call.methodName == 'sh' }.any { call -> callArgsToString(call).contains('docker push <registry>/my-repo/my-app:0.1.0') }).isTrue() assertJobStatusSuccess() } } * Source code shown is simulated for demo purposes only confirms the docker push command would be invoked correctly
  53. © 2019 All Rights Reserved. 53 // src/test/groovy/DockerBuildTest.groovy import static

    com.lesfurets.jenkins.unit.MethodCall.callArgsToString import static org.assertj.core.api.Assertions.assertThat import com.lesfurets.jenkins.unit.BasePipelineTest import org.junit.Test public class DockerBuildTest extends BasePipelineTest { // ... @Test void shouldPushToRegistry() { loadScript('dockerBuild/Jenkinsfile') printCallStack() assertThat(helper.callStack.findAll { call -> call.methodName == 'sh' }.any { call -> callArgsToString(call).contains('docker push <registry>/my-repo/my-app:0.1.0') }).isTrue() assertJobStatusSuccess() } } * Source code shown is simulated for demo purposes only confirms the job completed without an error
  54. © 2019 All Rights Reserved. 54 ➜ shared-libraries git:(master) ./gradlew

    test DockerBuildTest > shouldPushToRegistry STANDARD_OUT Loading shared library shared-libraries with version master Jenkinsfile.run() Jenkinsfile.stage(Build, groovy.lang.Closure) Jenkinsfile.dockerBuild({credentialsId=..., image=my-namespace/my-app:0.1.0, pushToRegistry=true, withProxy=true, withScan=true}) dockerBuild.node(docker, groovy.lang.Closure) dockerBuild.sh(docker build -t <registry>/my-repo/my-app:0.1.0 --build-arg https_proxy=http://<proxy>:8080 .) dockerBuild.sh({returnStdout=true, script=docker inspect <registry>/my-repo/my-app:0.1.0 -f '{{.ID}}'}) dockerBuild.usernamePassword({credentialsId=...}) dockerBuild.withCredentials([null], groovy.lang.Closure) dockerBuild.retry(3, groovy.lang.Closure) dockerBuild.sh(docker push <registry>/my-repo/my-app:0.1.0) Gradle Test Executor 47 finished executing tests. > Task :test Generating HTML test report… Finished generating test html results (0.002 secs) BUILD SUCCESSFUL in 4s 4 actionable tasks: 4 executed Stopped 1 worker daemon(s). * Source code shown is simulated for demo purposes only
  55. © 2019 All Rights Reserved. 55 The CI/CD Pipeline -

    Test // Jenkinsfile stage('Build') { steps { sh './gradlew assemble' } } stage('Test') { steps { sh './gradlew test' } } * Source code shown is simulated for demo purposes only
  56. © 2019 All Rights Reserved. 56

  57. © 2019 All Rights Reserved. 57 The CI/CD Pipeline -

    Test // Jenkinsfile library("shared-libraries@${env.BRANCH_NAME}") stage('Test') { steps { gradleBuild(tasks: 'test') ... } } * Source code shown is simulated for demo purposes only
  58. © 2019 All Rights Reserved. 58 The CI/CD Pipeline -

    Test // Jenkinsfile library("shared-libraries@${env.BRANCH_NAME}") stage('Test') { steps { gradleBuild(tasks: 'test') ... } } * Source code shown is simulated for demo purposes only
  59. © 2019 All Rights Reserved. 59 // Jenkinsfile library("shared-libraries@${env.BRANCH_NAME}") stage('Test')

    { steps { gradleBuild(tasks: 'test') ... } } The CI/CD Pipeline - Test * Source code shown is simulated for demo purposes only gradleBuild() is a custom library function!
  60. © 2019 All Rights Reserved. 60 // Jenkinsfile library("shared-libraries@${env.BRANCH_NAME}") stage('Test')

    { steps { gradleBuild(tasks: 'test') evaluate(readTrusted('test/dockerBuild/Jenkinsfile')) } } The CI/CD Pipeline - Test * Source code shown is simulated for demo purposes only executes a Jenkinsfile with library methods against the library itself!
  61. © 2019 All Rights Reserved. 61 // Jenkinsfile library("shared-libraries@${env.BRANCH_NAME}") stage('Test')

    { steps { gradleBuild(tasks: 'test') evaluate(readTrusted('test/dockerBuild/Jenkinsfile')) } } The CI/CD Pipeline - Test * Source code shown is simulated for demo purposes only executes a Jenkinsfile with library methods against the library itself!
  62. © 2019 All Rights Reserved. 62 The CI/CD Pipeline Build

    Test Release Rollback Checkpoint End Start
  63. © 2019 All Rights Reserved. 63 The CI/CD Pipeline -

    Release
  64. © 2019 All Rights Reserved. 64 The CI/CD Pipeline -

    Release ➜ curl -s https://<ghe>/api/v3/repos/<org>/<repo>/releases/latest | jq '.tag_name' "v0.3.95" * Source code shown is simulated for demo purposes only
  65. © 2019 All Rights Reserved. 65 The CI/CD Pipeline -

    Release * Source code shown is simulated for demo purposes only def libVersion = getLibraryVersion() echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline the bootstrap script
  66. © 2019 All Rights Reserved. 66 The CI/CD Pipeline -

    Release def getLibraryVersion() { def response = httpRequest( url: 'https://<ghe>/api/v3/repos/<org>/<repo>/releases/latest', httpMode: 'GET', contentType: 'APPLICATION_JSON', validResponseCodes: '200', ) return readJSON(text: response.content).tag_name } * Source code shown is simulated for demo purposes only
  67. © 2019 All Rights Reserved. 67 The CI/CD Pipeline -

    Release * Source code shown is simulated for demo purposes only def libVersion = getLibraryVersion() echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline the bootstrap script
  68. © 2019 All Rights Reserved. 68 def libVersion = "v0.3.95"

    echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline The CI/CD Pipeline - Release * Source code shown is simulated for demo purposes only the bootstrap script
  69. © 2019 All Rights Reserved. 69 The CI/CD Pipeline -

    Release master v0.1.0 latest
  70. © 2019 All Rights Reserved. 70 The CI/CD Pipeline -

    Release master v0.1.0 v0.1.1 latest
  71. © 2019 All Rights Reserved. 71 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 latest master
  72. © 2019 All Rights Reserved. 72 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 latest master
  73. © 2019 All Rights Reserved. 73 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 latest master
  74. © 2019 All Rights Reserved. 74 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 latest master
  75. © 2019 All Rights Reserved. 75 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 latest master
  76. © 2019 All Rights Reserved. 76 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 latest master
  77. © 2019 All Rights Reserved. 77 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 latest master
  78. © 2019 All Rights Reserved. 78 The CI/CD Pipeline -

    Release Canary release is a technique to reduce the risk of introducing a new software version in production by slowly rolling out the change to a small subset of users before rolling it out to the entire infrastructure and making it available to everybody. https://martinfowler.com/bliki/CanaryRelease.html “ “
  79. © 2019 All Rights Reserved. 79 The CI/CD Pipeline -

    Release Users Jenkins Instances 30% 70%
  80. © 2019 All Rights Reserved. 80 The CI/CD Pipeline -

    Release Users Jenkins Instances latest stable
  81. © 2019 All Rights Reserved. 81 The CI/CD Pipeline -

    Release v0.1.0 latest stable master
  82. © 2019 All Rights Reserved. 82 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 latest stable master
  83. © 2019 All Rights Reserved. 83 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 latest - 30% stable master
  84. © 2019 All Rights Reserved. 84 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 latest - 30% stable - 70% master
  85. © 2019 All Rights Reserved. 85 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  86. © 2019 All Rights Reserved. 86 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  87. © 2019 All Rights Reserved. 87 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  88. © 2019 All Rights Reserved. 88 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 latest - 30% stable - 70% master
  89. © 2019 All Rights Reserved. 89 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 latest - 30% stable - 70% master
  90. © 2019 All Rights Reserved. 90 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 latest - 30% stable - 70% master
  91. © 2019 All Rights Reserved. 91 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 latest - 30% stable - 70% master
  92. © 2019 All Rights Reserved. 92 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 v0.1.2 v0.1.3 v0.1.4 latest - 30% stable - 70% master
  93. © 2019 All Rights Reserved. 93 The CI/CD Pipeline -

    Release v0.1.0 v0.1.1 latest - 30% stable - 70% v0.1.2 v0.1.3 v0.1.4 master
  94. © 2019 All Rights Reserved. 94 The CI/CD Pipeline -

    Release * Source code shown is simulated for demo purposes only def libVersion = getLibraryVersion() echo "Using shared library version: ${libVersion}" library("jenkins-pipeline-library@${libVersion}") def pipeline = readTrusted 'Jenkinsfile' evaluate pipeline the bootstrap script
  95. © 2019 All Rights Reserved. 95 The CI/CD Pipeline -

    Release def getLibraryVersion() { if (env.JENKINS_URL =~ /<canaryjenkins1>|<canaryjenkins2>/) { def response = httpRequest( url: 'https://<ghe>/api/v3/repos/<org>/<repo>/releases/latest', httpMode: 'GET', contentType: 'APPLICATION_JSON', validResponseCodes: '200', ) return readJSON(text: response.content).tag_name } return 'stable' } * Source code shown is simulated for demo purposes only
  96. © 2019 All Rights Reserved. 96 The CI/CD Pipeline Build

    Test Release Rollback Checkpoint End Start
  97. © 2019 All Rights Reserved. 97 The CI/CD Pipeline -

    Rollback Checkpoint // Jenkinsfile stage('Rollback Checkpoint') { steps { timeout(time: 4, unit: 'HOURS') { input(message: "Rollback v${version}?", ok: 'Yes') } ... } } * Source code shown is simulated for demo purposes only
  98. © 2019 All Rights Reserved. 98 The CI/CD Pipeline -

    Rollback Checkpoint
  99. © 2019 All Rights Reserved. 99 The CI/CD Pipeline -

    Rollback Checkpoint def sendDatadogMetrics(def metrics) { try { httpRequest( url: 'https://app.datadoghq.com/api/v1/series, httpMode: 'POST', contentType: 'APPLICATION_JSON', requestBody: "{[\"series\": ${metrics}]}", validResponseCodes: '200,201,202,204', ) } catch (e) { null } } [ "job_name:${env.JOB_NAME}", "job_status:${currentBuild.currentResult}", "library_version:${libVersion}", "failure_exception_class:${error.getClass().getName()}", ] Tags * Source code shown is simulated for demo purposes only
  100. © 2019 All Rights Reserved. 100 The CI/CD Pipeline -

    Rollback Checkpoint v0.3.95 released hudson.AbortException
  101. © 2019 All Rights Reserved. 101

  102. © 2019 All Rights Reserved. 102 The CI/CD Pipeline -

    Rollback Checkpoint
  103. © 2019 All Rights Reserved. 103 The CI/CD Pipeline -

    Rollback Checkpoint
  104. © 2019 All Rights Reserved. 104 The CI/CD Pipeline -

    Rollback Checkpoint
  105. © 2019 All Rights Reserved. 105 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 latest - 30% stable - 70% master
  106. © 2019 All Rights Reserved. 106 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 latest - 30% stable - 70% 4 hours master
  107. © 2019 All Rights Reserved. 107 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  108. © 2019 All Rights Reserved. 108 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  109. © 2019 All Rights Reserved. 109 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% 4 hours master
  110. © 2019 All Rights Reserved. 110 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  111. © 2019 All Rights Reserved. 111 The CI/CD Pipeline -

    Rollback Checkpoint
  112. © 2019 All Rights Reserved. 112 The CI/CD Pipeline -

    Rollback Checkpoint
  113. © 2019 All Rights Reserved. 113 The CI/CD Pipeline -

    Rollback Checkpoint
  114. © 2019 All Rights Reserved. 114 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  115. © 2019 All Rights Reserved. 115 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  116. © 2019 All Rights Reserved. 116 The CI/CD Pipeline -

    Rollback Checkpoint
  117. © 2019 All Rights Reserved. 117 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  118. © 2019 All Rights Reserved. 118 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  119. © 2019 All Rights Reserved. 119 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% master
  120. © 2019 All Rights Reserved. 120 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 master
  121. © 2019 All Rights Reserved. 121 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 4 hours master
  122. © 2019 All Rights Reserved. 122 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 master
  123. © 2019 All Rights Reserved. 123 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 master
  124. © 2019 All Rights Reserved. 124 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 v0.1.4 master
  125. © 2019 All Rights Reserved. 125 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 v0.1.4 master
  126. © 2019 All Rights Reserved. 126 The CI/CD Pipeline -

    Rollback Checkpoint v0.1.0 v0.1.1 v0.1.2 latest - 30% stable - 70% v0.1.3 v0.1.4 master
  127. © 2019 All Rights Reserved. 127 The CI/CD Pipeline Build

    Test Release Rollback Checkpoint End Start
  128. © 2019 All Rights Reserved. 128 In closing...

  129. © 2019 All Rights Reserved. 129 In closing... https://wiki.jenkins.io/display/JENKINS/Pipeline+Shared+Groovy+Libraries+Plugin

  130. © 2019 All Rights Reserved. 130 In closing... Build Test

    Release Rollback Checkpoint End Start
  131. © 2019 All Rights Reserved. 131

  132. © 2019 All Rights Reserved. 132 Roderick R. Randolph linkedin.com/in/roderickrandolph

    capitalonecareers.com Distinguished Engineer Reimagining the software delivery experience for our engineers.
  133. Thank You!