Skip to main content
โšก Calmops

Continuous Integration and CI/CD

Continuous Integration and CI/CD

CI/CD automates testing and deployment. This article covers pipeline setup and best practices.

Introduction

CI/CD provides:

  • Automated testing
  • Automated deployment
  • Quality gates
  • Faster feedback
  • Reduced manual work

Understanding CI/CD helps you:

  • Automate workflows
  • Catch issues early
  • Deploy safely
  • Reduce errors
  • Improve velocity

GitHub Actions

Workflow Setup

# โœ… Good: GitHub Actions workflow
name: CI/CD

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set up Node.js
      uses: actions/setup-node@v3
      with:
        node-version: '18'
        cache: 'npm'

    - name: Install dependencies
      run: npm ci

    - name: Run linter
      run: npm run lint

    - name: Run tests
      run: npm test -- --coverage

    - name: Upload coverage
      uses: codecov/codecov-action@v3

  build:
    needs: test
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Build Docker image
      run: docker build -t myapp:${{ github.sha }} .

    - name: Push to registry
      run: |
        echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
        docker push myapp:${{ github.sha }}

  deploy:
    needs: build
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'

    steps:
    - name: Deploy to production
      run: |
        kubectl set image deployment/app app=myapp:${{ github.sha }}

GitLab CI

Pipeline Configuration

# โœ… Good: GitLab CI pipeline
stages:
  - test
  - build
  - deploy

variables:
  DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

test:
  stage: test
  image: node:18
  script:
    - npm ci
    - npm run lint
    - npm test -- --coverage
  coverage: '/Lines\s*:\s*(\d+\.\d+)%/'
  artifacts:
    reports:
      coverage_report:
        coverage_format: cobertura
        path: coverage/cobertura-coverage.xml

build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  script:
    - docker build -t $DOCKER_IMAGE .
    - docker push $DOCKER_IMAGE

deploy:
  stage: deploy
  image: bitnami/kubectl:latest
  script:
    - kubectl set image deployment/app app=$DOCKER_IMAGE
  only:
    - main

Jenkins Pipeline

Jenkinsfile

// โœ… Good: Jenkins pipeline
pipeline {
  agent any

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

    stage('Install') {
      steps {
        sh 'npm ci'
      }
    }

    stage('Lint') {
      steps {
        sh 'npm run lint'
      }
    }

    stage('Test') {
      steps {
        sh 'npm test -- --coverage'
      }
    }

    stage('Build') {
      steps {
        sh 'docker build -t myapp:${BUILD_NUMBER} .'
      }
    }

    stage('Deploy') {
      when {
        branch 'main'
      }
      steps {
        sh 'kubectl set image deployment/app app=myapp:${BUILD_NUMBER}'
      }
    }
  }

  post {
    always {
      junit 'test-results.xml'
      publishHTML([
        reportDir: 'coverage',
        reportFiles: 'index.html',
        reportName: 'Coverage Report'
      ])
    }
  }
}

Quality Gates

Code Quality Checks

# โœ… Good: Quality gates
jobs:
  quality:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v3

    - name: SonarQube scan
      uses: SonarSource/sonarcloud-github-action@master
      env:
        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

    - name: Check quality gate
      run: |
        if [ "$SONAR_QUALITY_GATE" != "PASSED" ]; then
          echo "Quality gate failed"
          exit 1
        fi

Best Practices

  1. Fail fast:

    # โœ… Good: Run fast checks first
    stages:
      - lint      # Fast
      - test      # Medium
      - build     # Slow
      - deploy    # Slowest
    
    # โŒ Bad: Run slow checks first
    stages:
      - build
      - deploy
      - test
      - lint
    
  2. Cache dependencies:

    # โœ… Good: Cache dependencies
    cache:
      paths:
        - node_modules/
    
    # โŒ Bad: No caching
    
  3. Use secrets:

    # โœ… Good: Use secrets
    - name: Deploy
      env:
        DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
      run: docker login -u user -p $DOCKER_PASSWORD
    
    # โŒ Bad: Hardcode credentials
    - name: Deploy
      run: docker login -u user -p password123
    

Summary

CI/CD is essential. Key takeaways:

  • Automate testing
  • Automate deployment
  • Implement quality gates
  • Cache dependencies
  • Use secrets
  • Fail fast
  • Monitor pipelines
  • Improve continuously

Next Steps

Comments