Session 04

Agenda

πŸš€ CI/CD Explained

CI/CD stands for:

  • CI β†’ Continuous Integration
  • CD β†’ Continuous Delivery / Continuous Deployment

These are essential practices in DevOps that help teams deliver software faster, more reliably, and with confidence.


πŸ”§ 1. What is CI (Continuous Integration)?

βœ… CI automates the process of merging and testing code frequently.

Key Concepts:

  • Developers push code frequently (e.g., daily)
  • Code is automatically built and tested via pipelines
  • Prevents “integration hell” at release time

Example Activities:

  • Compile/build the app
  • Run unit tests
  • Lint code
  • Package artifacts (e.g., .jar, .tar.gz)

πŸ“¦ 2. What is CD?

CD has two meanings:
Continuous Delivery or Continuous Deployment

Let’s break it down:


βœ… 2A. Continuous Delivery

Automates delivery of code to a staging environment or manual approval gate.

  • Code is tested and ready to deploy
  • Human approval is needed for production
  • Reduces time between development and release

πŸ§ͺ Ideal for teams that want control and automated testing, but manual production releases.


πŸš€ 2B. Continuous Deployment

Fully automates deployment to production with no manual steps.

  • Every successful commit is deployed to production
  • Requires robust test automation
  • Zero manual intervention

πŸ” Ideal for high-frequency release teams (e.g., Netflix, Amazon)


πŸ” CI/CD Pipeline Example Flow

Commit β†’ CI Build β†’ Unit Test β†’ Lint β†’ Integration Test β†’ Package β†’ CD Staging β†’ Manual Approval β†’ CD Production

In Continuous Deployment, the Manual Approval step is removed.


🧠 Benefits of CI/CD

BenefitCICD
Early bug detectionβœ…βœ…
Faster releasesβœ…βœ…
Automationβœ… Build/Testβœ… Deploy/Test
Developer confidenceβœ…βœ…
Customer satisfactionβœ… Faster feature delivery

πŸ› οΈ Tools for CI/CD

CategoryPopular Tools
CI PipelinesJenkins, GitLab CI, CircleCI
CD ToolsArgoCD, Spinnaker, Flux
TestingJUnit, Pytest, Selenium
ContainersDocker, Podman
OrchestrationKubernetes, Nomad

🧩 Summary Table

TermDescription
CIAutomate build and test after every commit
Continuous DeliveryReady to deploy with approval
Continuous DeploymentAutomatically deploy to production

🧱 Part 1: Install Jenkins

🐳 Part 2: Install Docker & Docker Compose

Test in Jenkins (via freestyle or pipeline job):

pipeline {
  agent any
  stages {
    stage('Docker Test') {
      steps {
        sh 'docker version'
        sh 'docker info'
      }
    }
  }
}

πŸš€ Part 3: Sample Jenkins Pipeline to Run Docker Compose App

pipeline {
  agent any

  environment {
    COMPOSE_PROJECT_DIR = "${WORKSPACE}/myapp"
  }

  stages {
    stage('Checkout') {
      steps {
        git 'https://github.com/nirpendra83/docker-compose.git'
      }
    }

    stage('Build and Deploy') {
      steps {
        dir('myapp') {
          sh 'docker-compose down --volumes || true'
          sh 'docker-compose up -d --build'
        }
      }
    }

    stage('Health Check') {
      steps {
        sh 'sleep 5 && curl -f http://localhost:5000'
      }
    }

    stage('Shutdown') {
      steps {
        dir('myapp') {
          sh 'docker-compose down'
        }
      }
    }
  }

  post {
    always {
      echo 'βœ… Pipeline complete. Clean up done.'
    }
  }
}
  • For Windows Jenkins agent
pipeline {
  agent any

  environment {
    COMPOSE_PROJECT_DIR = "${WORKSPACE}/myapp"
  }

  stages {
    stage('Checkout') {
      steps {
        git branch: 'main', url: 'https://github.com/nirpendra83/docker-compose.git'
      }
    }

    stage('Build and Deploy') {
      steps {
        dir('myapp') {
          bat 'docker-compose down --volumes || true'
          bat 'docker-compose up -d --build'
        }
      }
    }

    stage('Health Check') {
      steps {
        bat 'sleep 5 && curl -f http://localhost:5000'
      }
    }

    stage('Shutdown') {
      steps {
        dir('myapp') {
          bat 'docker-compose down'
        }
      }
    }
  }

  post {
    always {
      echo 'βœ… Pipeline complete. Clean up done.'
    }
  }
}

πŸ’‘ Jenkins Declarative Pipeline Guide

The Declarative Pipeline in Jenkins is a structured way to define CI/CD workflows using a Jenkinsfile. It is easier to read, validate, and maintain compared to Scripted Pipelines.


🧱 1. Basic Structure

pipeline {
  agent any
  stages {
    stage('Example') {
      steps {
        echo 'Hello World'
      }
    }
  }
}

πŸš€ 2. agent Block

The agent defines where the pipeline or a specific stage runs.

πŸ”Ή Global Agent

agent any

πŸ”Ή Label-based Agent

agent { label 'docker-node' }

πŸ”Ή Docker Agent

agent {
  docker {
    image 'python:3.10'
    args '-p 5000:5000'
  }
}

πŸ”Ή No Agent Globally (define per stage)

pipeline {
  agent none
  stages {
    stage('Build') {
      agent any
      steps {
        echo "Building..."
      }
    }
  }
}

🌍 3. environment Block

Defines environment variables, globally or per stage.

environment {
  MY_ENV = 'production'
  PATH = "/custom/bin:${env.PATH}"
}

πŸ§ͺ 4. parameters Block

Used for user input when starting a pipeline manually.

parameters {
  string(name: 'VERSION', defaultValue: '1.0.0', description: 'Release version')
  booleanParam(name: 'RUN_TESTS', defaultValue: true, description: 'Run tests?')
}

Use with: ${params.VERSION}, ${params.RUN_TESTS}


🧱 5. stages and steps

  • Stages are logical divisions like “Build”, “Test”, “Deploy”
  • Steps are shell commands or Jenkins actions
stages {
  stage('Build') {
    steps {
      echo "Building version ${params.VERSION}"
      sh 'make build'
    }
  }
}

🧼 6. post Block

Defines actions to run after the pipeline or a stage, based on outcome.

post {
  always {
    echo 'Always runs'
  }
  success {
    echo 'Runs on success'
  }
  failure {
    echo 'Runs on failure'
  }
  unstable {
    echo 'Runs if build is unstable'
  }
  changed {
    echo 'Runs if result changed since last run'
  }
}

🎯 7. when Block

Run a stage only if conditions are met.

stage('Deploy') {
  when {
    branch 'main'
  }
  steps {
    sh './deploy.sh'
  }
}

Other options:

  • expression { return params.RUN_TESTS }
  • environment name: 'ENV_VAR', value: 'prod'
  • not, anyOf, allOf for combining conditions

πŸ”€ 8. Parallel Stages

stage('Test Suite') {
  parallel {
    stage('Unit Tests') {
      steps { sh 'pytest tests/unit' }
    }
    stage('Integration Tests') {
      steps { sh 'pytest tests/integration' }
    }
  }
}

πŸ”§ 9. Error Handling

Explicit failure:

steps {
  error("Stopping pipeline due to failure")
}

Retry logic:

steps {
  retry(3) {
    sh './sometimes-fails.sh'
  }
}

🧠 10. Built-in Variables

VariableDescription
env.BUILD_IDUnique ID for the current build
env.BUILD_NUMBERBuild number
env.JOB_NAMEName of the job
params.<name>Access input parameters
env.WORKSPACEFile path of the working directory

πŸ“¦ Example: Full Declarative Pipeline

pipeline {
  agent any

  parameters {
    string(name: 'VERSION', defaultValue: '1.0.0')
  }

  environment {
    DEPLOY_ENV = 'staging'
  }

  stages {
    stage('Build') {
      steps {
        echo "Building version ${params.VERSION}"
      }
    }

    stage('Test') {
      steps {
        sh './run_tests.sh'
      }
    }

    stage('Deploy') {
      when {
        branch 'main'
      }
      steps {
        sh './deploy.sh ${params.VERSION}'
      }
    }
  }

  post {
    success {
      echo 'βœ… Build succeeded.'
    }
    failure {
      echo '❌ Build failed.'
    }
    always {
      echo '🧹 Cleaning up...'
    }
  }
}

βœ… Declarative pipelines are YAML-like Groovy configurations that make your Jenkins workflows repeatable, testable, and easy to maintain.