Skip to content

Fawkes Dojo Module 5: Continuous Integration Fundamentals

🎯 Module Overview

Belt Level: 🟑 Yellow Belt - CI/CD Mastery Module: 1 of 4 (Yellow Belt) Duration: 60 minutes Difficulty: Intermediate Prerequisites:

  • White Belt certification complete
  • Basic understanding of Git workflows
  • Familiarity with build tools (Maven, npm, etc.)
  • Command line comfort

πŸ“š Learning Objectives

By the end of this module, you will:

  1. βœ… Explain the principles and benefits of Continuous Integration
  2. βœ… Understand Jenkins architecture and core concepts
  3. βœ… Create your first Jenkinsfile (Pipeline as Code)
  4. βœ… Configure build stages: checkout, build, test, package
  5. βœ… Implement basic error handling and notifications
  6. βœ… Understand how CI improves DORA metrics
  7. βœ… Troubleshoot common CI pipeline failures

DORA Capabilities Addressed:

  • βœ“ CD3: Implement continuous integration
  • βœ“ CD1: Use version control for all production artifacts
  • βœ“ CD5: Trunk-based development methods

πŸ“– Part 1: What is Continuous Integration?

The Problem: Integration Hell

Traditional development workflow:

Developer A writes code for 2 weeks β†’ Commits
Developer B writes code for 2 weeks β†’ Commits
Developer C writes code for 2 weeks β†’ Commits
                ↓
        Integration Day (Friday)
                ↓
      Merge conflicts, broken tests
      Incompatible changes, missing dependencies
                ↓
        Weekend fixing integration issues

Result:

  • Integration becomes painful and risky
  • Feedback delayed by weeks
  • Bugs found late, expensive to fix
  • Releases delayed, stress increases

Continuous Integration Solution

"Integrate early, integrate often"

Developer A: Commits multiple times per day
         ↓
    Automated Build + Test
         ↓
    Immediate Feedback (5-10 min)
         ↓
    Fix issues immediately
         ↓
    Always in releasable state

Core CI Principles

  1. Maintain a Single Source Repository

  2. All code in version control

  3. One repo truth source
  4. Branches short-lived (<1 day)

  5. Automate the Build

  6. One command builds everything

  7. No manual steps
  8. Repeatable and reliable

  9. Make Your Build Self-Testing

  10. Automated unit tests

  11. Integration tests
  12. Build fails if tests fail

  13. Everyone Commits to Mainline Every Day

  14. Small, frequent commits

  15. Merge conflicts minimized
  16. Continuous integration (the name!)

  17. Every Commit Should Build on Integration Machine

  18. Not "works on my machine"

  19. Clean environment every time
  20. Same as production

  21. Keep the Build Fast

  22. Target: <10 minutes

  23. Developers wait for feedback
  24. Slow builds = ignored builds

  25. Test in Clone of Production Environment

  26. Same OS, same dependencies

  27. Containers/VMs for consistency
  28. "Shift left" on environment issues

  29. Make it Easy to Get Latest Deliverables

  30. Artifacts automatically published

  31. Always available for testing
  32. Clear versioning

  33. Everyone Can See What's Happening

  34. Build status visible to all

  35. Radiator dashboards
  36. Notifications on failures

  37. Automate Deployment

    • One-click deployment
    • Continuous Delivery (next step)
    • Reduces human error

CI Impact on DORA Metrics

DORA Metric CI Impact Data
Deployment Frequency Enables multiple deploys/day with confidence Elite: Multiple per day
Lead Time for Changes Reduces commit-to-deploy from days to minutes Elite: <1 hour
Change Failure Rate Catches bugs before production Elite: 0-15%
MTTR Small changes = easier rollback Elite: <1 hour

Research shows: Teams with CI are 2x more likely to be high performers on DORA metrics.


πŸ—οΈ Part 2: Jenkins Architecture

What is Jenkins?

Jenkins is an open-source automation server that enables CI/CD pipelines.

Key Features:

  • Pipeline as Code (Jenkinsfile)
  • 1,800+ plugins for integration
  • Distributed builds (controller + agents)
  • Kubernetes-native (Fawkes uses Kubernetes Plugin)
  • Web UI for monitoring and management

Jenkins Architecture in Fawkes

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           Fawkes Platform (Kubernetes)              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚      Jenkins Controller (Master)             β”‚  β”‚
β”‚  β”‚  β€’ Manages pipelines                         β”‚  β”‚
β”‚  β”‚  β€’ Schedules builds                          β”‚  β”‚
β”‚  β”‚  β€’ Stores configuration                      β”‚  β”‚
β”‚  β”‚  β€’ Serves Web UI                             β”‚  β”‚
β”‚  β”‚  β€’ Kubernetes Plugin installed               β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                  β”‚                                  β”‚
β”‚                  β”‚ (Schedules agents)               β”‚
β”‚                  β–Ό                                  β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  Dynamic Build Agents (Pods)                 β”‚  β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚  β”‚
β”‚  β”‚  β”‚ Java     β”‚  β”‚ Node.js  β”‚  β”‚ Python   β”‚   β”‚  β”‚
β”‚  β”‚  β”‚ Agent    β”‚  β”‚ Agent    β”‚  β”‚ Agent    β”‚   β”‚  β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚  β”‚
β”‚  β”‚  β€’ Created on-demand                         β”‚  β”‚
β”‚  β”‚  β€’ Isolated namespaces                       β”‚  β”‚
β”‚  β”‚  β€’ Auto-deleted after build                  β”‚  β”‚
β”‚  β”‚  β€’ Resource limits enforced                  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                                                     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚      Supporting Services                     β”‚  β”‚
β”‚  β”‚  β€’ Git Repository (Source)                   β”‚  β”‚
β”‚  β”‚  β€’ Harbor (Artifact Registry)                β”‚  β”‚
β”‚  β”‚  β€’ SonarQube (Code Quality)                  β”‚  β”‚
β”‚  β”‚  β€’ Trivy (Security Scanning)                 β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Jenkins Controller vs. Agents

Controller (Master):

  • Orchestrates builds
  • Manages plugins and configuration
  • Serves Web UI
  • Should NOT run builds (security + resource management)

Agents (Slaves/Pods):

  • Execute actual build work
  • Ephemeral in Kubernetes
  • Isolated from each other
  • Deleted after build completes

Fawkes Advantage: Using Kubernetes Plugin, agents are dynamic pods. No pre-provisioned VMs needed!

Pipeline as Code: Jenkinsfile

Modern Jenkins uses declarative pipelines defined in Jenkinsfile:

Benefits:

  • βœ… Version controlled with code
  • βœ… Code review for pipeline changes
  • βœ… Consistent across projects
  • βœ… Auditable (Git history)
  • βœ… Portable across Jenkins instances

πŸ› οΈ Part 3: Hands-On Lab - Your First Pipeline

Lab Scenario

You'll create a CI pipeline for a sample Java Spring Boot application that:

  1. Checks out code from Git
  2. Compiles the application
  3. Runs unit tests
  4. Packages as Docker image
  5. Pushes to Harbor registry

Step 1: Access Your Lab Environment

# Access Jenkins in Fawkes platform
kubectl port-forward -n jenkins svc/jenkins 8080:8080

# Get Jenkins admin password
kubectl get secret -n jenkins jenkins-admin -o jsonpath="{.data.password}" | base64 -d

# Open Jenkins UI
# URL: http://localhost:8080
# Username: admin
# Password: (from above command)

Step 2: Create Your First Pipeline Job

In Jenkins UI:

  1. Click "New Item"
  2. Name: my-first-pipeline
  3. Type: "Pipeline"
  4. Click "OK"

Pipeline Configuration:

  • Scroll to "Pipeline" section
  • Definition: "Pipeline script"
  • Paste the following script:
pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
metadata:
  labels:
    jenkins: agent
spec:
  containers:
  - name: maven
    image: maven:3.8-openjdk-17
    command:
    - sleep
    args:
    - infinity
  - name: docker
    image: docker:24-dind
    securityContext:
      privileged: true
'''
        }
    }

    stages {
        stage('Checkout') {
            steps {
                echo 'Checking out source code...'
                git branch: 'main',
                    url: 'https://github.com/fawkes-platform/sample-spring-boot.git'
            }
        }

        stage('Build') {
            steps {
                container('maven') {
                    echo 'Building application...'
                    sh 'mvn clean compile'
                }
            }
        }

        stage('Test') {
            steps {
                container('maven') {
                    echo 'Running tests...'
                    sh 'mvn test'
                }
            }
        }

        stage('Package') {
            steps {
                container('maven') {
                    echo 'Packaging application...'
                    sh 'mvn package -DskipTests'
                }
            }
        }
    }

    post {
        success {
            echo 'βœ… Pipeline succeeded!'
        }
        failure {
            echo '❌ Pipeline failed!'
        }
        always {
            echo '🏁 Pipeline completed'
        }
    }
}
  1. Click "Save"
  2. Click "Build Now"

Step 3: Watch Your Pipeline Execute

In the Jenkins UI:

  • Click on the build number (e.g., #1)
  • Click "Console Output" to see logs in real-time
  • Watch as stages progress: Checkout β†’ Build β†’ Test β†’ Package

Expected Output:

Started by user admin
Running in Durability level: MAX_SURVIVABILITY
[Pipeline] Start of Pipeline
[Pipeline] podTemplate
[Pipeline] {
[Pipeline] node
Created Pod: jenkins-agent-xxxxx
Agent maven-xxxxx is provisioned from template maven
[Pipeline] {
[Pipeline] stage (Checkout)
[Pipeline] { (Checkout)
[Pipeline] echo
Checking out source code...
[Pipeline] git
Cloning repository https://github.com/fawkes-platform/sample-spring-boot.git
...
[Pipeline] stage (Build)
[Pipeline] { (Build)
[Pipeline] container
[Pipeline] {
[Pipeline] echo
Building application...
[Pipeline] sh
+ mvn clean compile
[INFO] Scanning for projects...
[INFO] Building sample-app 1.0.0
...
[INFO] BUILD SUCCESS
...

Step 4: Understanding the Jenkinsfile

Let's break down each section:

Agent Definition

agent {
    kubernetes {
        yaml '''
        ...
        '''
    }
}
  • Tells Jenkins to run this pipeline on a Kubernetes pod
  • Defines container images needed (Maven, Docker)
  • Containers are ephemeral - created for this build, deleted after

Stages

stages {
    stage('Checkout') { ... }
    stage('Build') { ... }
    stage('Test') { ... }
    stage('Package') { ... }
}
  • Sequential steps in your pipeline
  • Each stage appears as a column in Jenkins UI
  • Stages fail fast - if one fails, subsequent stages don't run

Steps

steps {
    container('maven') {
        sh 'mvn clean compile'
    }
}
  • Actual commands executed
  • container('maven') - runs inside Maven container
  • sh - executes shell command
  • Can use echo, git, custom plugins

Post Actions

post {
    success { ... }
    failure { ... }
    always { ... }
}
  • Runs after all stages complete
  • success - only if pipeline succeeded
  • failure - only if pipeline failed
  • always - regardless of outcome
  • Perfect for notifications, cleanup

πŸ“Š Part 4: Understanding Build Stages

Standard CI Pipeline Stages

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Checkout β”‚ β†’ β”‚ Build β”‚ β†’ β”‚ Test β”‚ β†’ β”‚ Package β”‚ β†’ β”‚ Publishβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜
     2s           3m          2m          1m            30s

Stage 1: Checkout

Purpose: Get source code from version control

stage('Checkout') {
    steps {
        git branch: 'main',
            url: 'https://github.com/org/repo.git',
            credentialsId: 'github-credentials'
    }
}

Best Practices:

  • Always specify branch explicitly
  • Use shallow clone for speed: git clone --depth 1
  • Store credentials in Jenkins Credentials Store (never in Jenkinsfile!)

Stage 2: Build/Compile

Purpose: Compile source code, resolve dependencies

stage('Build') {
    steps {
        container('maven') {
            sh '''
                mvn clean compile \
                    -DskipTests \
                    -B \
                    --batch-mode
            '''
        }
    }
}

Key Flags:

  • -DskipTests - Skip tests during compile (run separately)
  • -B / --batch-mode - Non-interactive, better for CI logs
  • clean - Remove previous build artifacts

Build Duration Targets:

  • Small projects: <2 minutes
  • Medium projects: 2-5 minutes
  • Large projects: 5-10 minutes
  • If >10 minutes, optimize (covered in Module 6)

Stage 3: Test

Purpose: Run automated tests, verify functionality

stage('Test') {
    steps {
        container('maven') {
            sh 'mvn test'
        }
    }
    post {
        always {
            junit 'target/surefire-reports/**/*.xml'
        }
    }
}

Test Types in CI:

  • Unit Tests: Fast (<1s each), no external dependencies
  • Integration Tests: Slower (1-10s), may use database/APIs
  • Contract Tests: Verify API contracts between services

Best Practices:

  • Run unit tests in every build (fast feedback)
  • Run integration tests in parallel or on schedule
  • Fail build if tests fail (quality gate)
  • Publish test reports with junit step

Stage 4: Package

Purpose: Create deployable artifact (JAR, Docker image, etc.)

stage('Package') {
    steps {
        container('maven') {
            sh 'mvn package -DskipTests'
        }
        container('docker') {
            sh '''
                docker build -t myapp:${BUILD_NUMBER} .
                docker tag myapp:${BUILD_NUMBER} myapp:latest
            '''
        }
    }
}

Artifact Versioning:

  • Use ${BUILD_NUMBER} - Jenkins build number (e.g., myapp:142)
  • Use ${GIT_COMMIT} - Git commit SHA (e.g., myapp:abc1234)
  • Use semantic versioning for releases (e.g., myapp:1.2.3)

Stage 5: Publish (Optional for Module 5)

Purpose: Push artifacts to registry

stage('Publish') {
    steps {
        container('docker') {
            sh '''
                docker login harbor.fawkes.internal -u ${HARBOR_USER} -p ${HARBOR_PASS}
                docker push harbor.fawkes.internal/myapp:${BUILD_NUMBER}
            '''
        }
    }
}

We'll cover this in detail in Module 8: Artifact Management


πŸ” Part 5: Error Handling & Debugging

Common Pipeline Failures

Issue 1: Checkout Fails

Error:

ERROR: Error cloning remote repo 'origin'
hudson.plugins.git.GitException: Command "git fetch" returned status code 128

Causes:

  • Repository URL incorrect
  • No access credentials configured
  • Network issues

Solutions:

// Option 1: Use credentials
git branch: 'main',
    url: 'https://github.com/org/private-repo.git',
    credentialsId: 'github-pat'

// Option 2: Use SSH
git branch: 'main',
    url: 'git@github.com:org/private-repo.git',
    credentialsId: 'github-ssh-key'

// Option 3: Check connectivity
sh 'git ls-remote https://github.com/org/repo.git HEAD'

Issue 2: Build Fails

Error:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile
[ERROR] Compilation failure: Compilation failure:
[ERROR] /src/main/java/App.java:[10,8] cannot find symbol

Causes:

  • Compilation errors in code
  • Missing dependencies
  • Wrong Java version

Solutions:

// Specify Java version
stage('Build') {
    steps {
        container('maven') {
            sh '''
                java -version
                mvn -version
                mvn clean compile
            '''
        }
    }
}

// Use specific Maven image
agent {
    kubernetes {
        yaml '''
        containers:
        - name: maven
          image: maven:3.8-openjdk-17  # Specific version
        '''
    }
}

Issue 3: Tests Fail

Error:

[ERROR] Tests run: 10, Failures: 2, Errors: 0, Skipped: 0
[INFO] BUILD FAILURE

Causes:

  • Actual bugs in code (good thing CI caught it!)
  • Test environment not set up correctly
  • Flaky tests (tests that randomly fail)

Solutions:

stage('Test') {
    steps {
        container('maven') {
            // Run with detailed output
            sh 'mvn test -X'  // Debug mode

            // Or continue on failure to see all test results
            sh 'mvn test || true'
        }
    }
    post {
        always {
            // Always publish test results
            junit 'target/surefire-reports/**/*.xml'

            // Archive failed test logs
            archiveArtifacts artifacts: 'target/surefire-reports/**',
                             allowEmptyArchive: true
        }
    }
}

Issue 4: Resource Limits

Error:

java.lang.OutOfMemoryError: Java heap space

Causes:

  • Build requires more memory than allocated
  • Memory leak in build process

Solutions:

agent {
    kubernetes {
        yaml '''
        containers:
        - name: maven
          image: maven:3.8-openjdk-17
          resources:
            requests:
              memory: "2Gi"
              cpu: "1000m"
            limits:
              memory: "4Gi"
              cpu: "2000m"
          env:
          - name: MAVEN_OPTS
            value: "-Xmx3g"  # Increase heap size
        '''
    }
}

Debugging Techniques

1. Add Verbose Logging

stage('Debug') {
    steps {
        sh '''
            echo "Current directory: $(pwd)"
            echo "Files present:"
            ls -la
            echo "Java version:"
            java -version
            echo "Maven version:"
            mvn -version
            echo "Environment variables:"
            env | sort
        '''
    }
}

2. Use Try-Catch

stage('Build with Error Handling') {
    steps {
        script {
            try {
                sh 'mvn clean compile'
            } catch (Exception e) {
                echo "Build failed with error: ${e.message}"
                // Send notification, mark unstable, etc.
                currentBuild.result = 'UNSTABLE'
            }
        }
    }
}

3. Access Agent Shell

// Add this stage temporarily for debugging
stage('Debug Shell') {
    steps {
        container('maven') {
            sh 'sleep 3600'  // Keeps container alive for 1 hour
        }
    }
}

// Then connect to pod:
// kubectl exec -it <pod-name> -c maven -- /bin/bash

🎯 Part 6: CI Best Practices

1. Keep Builds Fast

Target: <10 minutes total

Techniques:

  • Run only essential tests in CI (unit tests)
  • Parallelize independent stages
  • Cache dependencies
  • Use incremental compilation
pipeline {
    options {
        timestamps()
        timeout(time: 10, unit: 'MINUTES')  // Fail if >10 min
    }

    stages {
        stage('Parallel Tests') {
            parallel {
                stage('Unit Tests') {
                    steps {
                        sh 'mvn test'
                    }
                }
                stage('Linting') {
                    steps {
                        sh 'mvn checkstyle:check'
                    }
                }
            }
        }
    }
}

2. Fail Fast

Stop pipeline as soon as a critical issue is found.

pipeline {
    options {
        skipDefaultCheckout()  // Don't checkout until needed
    }

    stages {
        stage('Pre-Flight Checks') {
            steps {
                // Check if branch name follows convention
                script {
                    if (!env.BRANCH_NAME.matches(/(main|develop|feature\/.+)/)) {
                        error("Invalid branch name: ${env.BRANCH_NAME}")
                    }
                }
            }
        }

        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        // ... rest of pipeline
    }
}

3. Notifications

Keep team informed of build status.

post {
    success {
        slackSend(
            color: 'good',
            message: "βœ… Build #${BUILD_NUMBER} succeeded\nBranch: ${env.BRANCH_NAME}"
        )
    }

    failure {
        slackSend(
            color: 'danger',
            message: "❌ Build #${BUILD_NUMBER} failed\nBranch: ${env.BRANCH_NAME}\nSee: ${BUILD_URL}"
        )

        // Email on failure
        emailext(
            subject: "Build Failed: ${env.JOB_NAME} #${BUILD_NUMBER}",
            body: "Check console output at ${BUILD_URL}",
            to: "${env.CHANGE_AUTHOR_EMAIL}"
        )
    }
}

4. Environment Variables

Use environment variables for configuration.

pipeline {
    environment {
        APP_NAME = 'my-spring-boot-app'
        HARBOR_REGISTRY = 'harbor.fawkes.internal'
        JAVA_VERSION = '17'
        MAVEN_OPTS = '-Xmx2g -XX:+UseG1GC'
    }

    stages {
        stage('Build') {
            steps {
                sh """
                    echo "Building ${APP_NAME} with Java ${JAVA_VERSION}"
                    mvn clean package
                """
            }
        }
    }
}

5. Shared Libraries (Preview)

Reuse pipeline code across projects.

// In Jenkinsfile
@Library('fawkes-pipeline-library') _

fawkesJavaPipeline {
    gitRepo = 'https://github.com/org/repo.git'
    javaVersion = '17'
    runTests = true
    publishArtifacts = true
}

We'll cover this in Module 6: Golden Path Pipelines


πŸ“ˆ Part 7: CI Impact on DORA Metrics

How CI Improves Each Metric

1. Deployment Frequency

Without CI:
- Manual testing before each deploy
- Fear of breaking production
- Result: Deploy 1x per month

With CI:
- Automated testing on every commit
- Confidence in code quality
- Result: Deploy 10x per day

2. Lead Time for Changes

Without CI:
Commit β†’ Manual build (30 min) β†’ Manual test (2 hours) β†’ Package (30 min)
= 3+ hours before deploy-ready

With CI:
Commit β†’ Auto build (3 min) β†’ Auto test (2 min) β†’ Auto package (1 min)
= 6 minutes before deploy-ready

3. Change Failure Rate

Without CI:
- No automated testing
- Bugs reach production
- Result: 30% of deploys fail

With CI:
- Automated tests catch 80% of bugs
- Code review before merge
- Result: 5% of deploys fail

4. MTTR (Mean Time to Restore)

Without CI:
- Large commits, hard to isolate issue
- Manual rollback process
- Result: 2+ hours to restore

With CI:
- Small commits, easy to identify culprit
- Automated rollback
- Result: 10 minutes to restore

Measuring CI Effectiveness

Track these metrics in your Jenkins/Fawkes dashboard:

// Add to pipeline for metrics collection
post {
    always {
        script {
            def buildDuration = currentBuild.duration / 1000  // seconds
            def buildResult = currentBuild.result ?: 'SUCCESS'

            // Send to Prometheus
            sh """mayhem
                curl -X POST http://prometheus-pushgateway:9091/metrics/job/jenkins \
                    --data-binary @- <<EOF
# TYPE jenkins_build_duration_seconds gauge
jenkins_build_duration_seconds{job="${env.JOB_NAME}",result="${buildResult}"} ${buildDuration}

# TYPE jenkins_build_result counter
jenkins_build_result{job="${env.JOB_NAME}",result="${buildResult}"} 1
EOF
            """
        }
    }
}

πŸ’ͺ Part 8: Practical Exercise

Exercise: Build Your First Real Pipeline

Objective: Create a CI pipeline for a sample application

Scenario: You have a Java Spring Boot REST API that needs CI.

Requirements:

  1. Checkout code from Git
  2. Compile with Maven
  3. Run unit tests
  4. Package as JAR
  5. Build Docker image
  6. Send Slack notification on failure

Starter Code:

pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  containers:
  - name: maven
    image: maven:3.8-openjdk-17
    command: ['sleep']
    args: ['infinity']
  - name: docker
    image: docker:24-dind
    securityContext:
      privileged: true
    command: ['sleep']
    args: ['infinity']
'''
        }
    }

    stages {
        // TODO: Add your stages here
        // 1. Checkout
        // 2. Build
        // 3. Test
        // 4. Package
        // 5. Docker Build
    }

    post {
        // TODO: Add notifications
    }
}

Validation Criteria:

  • [ ] Pipeline runs successfully
  • [ ] All stages complete in <8 minutes
  • [ ] Test results published to Jenkins
  • [ ] Docker image created
  • [ ] Notification sent (Slack or email)

Submission:

  1. Save your Jenkinsfile to Git repository
  2. Run pipeline successfully (screenshot)
  3. Show console output
  4. Submit repository link

πŸŽ“ Part 9: Knowledge Check

Quiz Questions

  1. What is the primary goal of Continuous Integration?

  2. [ ] Deploy to production automatically

  3. [x] Integrate code changes frequently and catch issues early
  4. [ ] Write better documentation
  5. [ ] Reduce server costs

  6. How often should developers commit to mainline in CI?

  7. [ ] Once per week

  8. [ ] Once per sprint
  9. [x] At least once per day
  10. [ ] Only when feature is complete

  11. What is the recommended maximum build time?

  12. [ ] 30 minutes

  13. [x] 10 minutes
  14. [ ] 1 hour
  15. [ ] As long as it takes

  16. In Jenkins Kubernetes Plugin, what happens to build agents after build?

  17. [ ] They remain running for next build

  18. [x] They are automatically deleted
  19. [ ] They are paused
  20. [ ] They are archived

  21. Which stage should run first in a CI pipeline?

  22. [ ] Test

  23. [ ] Package
  24. [x] Checkout
  25. [ ] Deploy

  26. What does "fail fast" mean in CI?

  27. [ ] Make builds run faster

  28. [x] Stop pipeline immediately when critical issue found
  29. [ ] Skip tests to save time
  30. [ ] Deploy even if tests fail

  31. What file defines Jenkins Pipeline as Code?

  32. [ ] pipeline.yaml

  33. [x] Jenkinsfile
  34. [ ] build.xml
  35. [ ] ci-config.json

  36. Which DORA metric is most directly improved by CI?

  37. [ ] Deployment Frequency
  38. [x] Lead Time for Changes
  39. [ ] MTTR
  40. [ ] All of the above

Answers: 1-B, 2-C, 3-B, 4-B, 5-C, 6-B, 7-B, 8-D


🎯 Part 10: Module Summary & Next Steps

What You Learned

βœ… CI Principles: Early integration, automated builds, fast feedback βœ… Jenkins Architecture: Controller, agents, Kubernetes plugin βœ… Pipeline as Code: Jenkinsfile structure and syntax βœ… Build Stages: Checkout, build, test, package workflow βœ… Troubleshooting: Common failures and debugging techniques βœ… Best Practices: Fast builds, fail fast, notifications βœ… DORA Impact: How CI improves all four key metrics

DORA Capabilities Achieved

  • βœ… CD3: Continuous Integration implemented
  • βœ… CD1: Version control for production artifacts
  • βœ… CD5: Trunk-based development support

Key Takeaways

  1. CI is about feedback speed - The faster you know about problems, the cheaper they are to fix
  2. Automate everything - If it can be automated, it should be automated
  3. Keep builds fast - Developers won't wait for slow builds
  4. Fail fast - Don't waste time on builds that will fail anyway
  5. Make failures visible - Everyone should see broken builds immediately

Real-World Impact

"Before CI, our integration process took 2-3 days and often failed. After implementing CI with Jenkins:

  • Build time: 3 hours β†’ 8 minutes
  • Integration time: 3 days β†’ Continuous
  • Bug detection: Post-production β†’ Pre-commit
  • Deploy confidence: Low β†’ High

We went from monthly releases to daily deploys."

  • Engineering Team, SaaS Company

πŸ“š Additional Resources

Official Documentation

Learning Resources

Community


πŸ… Module Completion

Assessment Checklist

To complete this module, you must:

  • [ ] Conceptual Understanding

  • [ ] Explain the 10 principles of CI

  • [ ] Describe Jenkins controller vs. agent architecture
  • [ ] Explain how CI improves DORA metrics

  • [ ] Practical Skills

  • [ ] Create a Jenkinsfile from scratch

  • [ ] Configure Kubernetes agent pod template
  • [ ] Implement checkout, build, test, package stages
  • [ ] Add error handling and notifications
  • [ ] Debug a failed pipeline

  • [ ] Hands-On Lab

  • [ ] Complete the first pipeline lab

  • [ ] Pipeline runs successfully (<10 min)
  • [ ] All tests pass
  • [ ] Docker image created

  • [ ] Quiz

  • [ ] Score 80% or higher (6/8 questions)

Certification Credit

Upon completion, you earn:

  • 5 points toward Yellow Belt certification (25% complete)
  • Badge: "CI Practitioner"
  • Skill Unlocked: Jenkins Pipeline Creation

πŸŽ–οΈ Yellow Belt Progress

Yellow Belt: CI/CD Mastery
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Module 5: CI Fundamentals        β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘ 25% βœ“
Module 6: Golden Path Pipelines  β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  0%
Module 7: Security & Quality     β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  0%
Module 8: Artifact Management    β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘  0%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Next Module Preview: Module 6 - Building Golden Path Pipelines (Shared libraries, pipeline templates, optimization)


πŸŽ‰ Congratulations! You've completed Module 5 and learned the fundamentals of Continuous Integration with Jenkins.

You're now ready to build production-ready CI pipelines. Continue to Module 6 to learn how to create reusable, optimized pipeline templates!


Fawkes Dojo - Where Platform Engineers Are Forged Version 1.0 | Last Updated: October 2025 License: MIT | https://github.com/paruff/fawkes