DevOps · 35 Days · Week 3 Day 11 — CI/CD Concepts & Tool Landscape
1 / 22
Week 3 · Day 11 · CI/CD Starts

CI/CD Concepts & Tool Landscape

CI vs CD vs Continuous Deployment. Pipeline anatomy. Jenkins vs GitHub Actions vs GitLab CI — three tools that dominate every DevOps job description. Understand all three, be hireable anywhere.

⏱ Duration 60 min
📖 Theory 30 min
🔧 Lab 25 min
❓ Quiz 5 min
Week 3 — CI/CD with GitHub Actions & Jenkins Git push → pipeline trigger
Session Overview

What we cover today

01
CI vs CD vs Continuous Deployment
Three terms everyone confuses. Clear definitions, real examples, and how organisations progress through them.
02
Anatomy of a CI/CD Pipeline
Trigger → Build → Test → Security → Package → Deploy. What happens at each stage and why.
03
Tool Landscape: Jenkins vs GitHub Actions vs GitLab CI
Architecture, strengths, trade-offs. Why job ads say "Jenkins for enterprise, GitHub Actions for SaaS."
04
Jenkins Architecture Deep Dive
Controller-Agent model, Jenkinsfile, Job types — everything you need before writing your first pipeline.
05
GitHub Actions Architecture
Workflows, jobs, steps, runners, marketplace actions — the YAML anatomy explained.
06
Side-by-Side: Same Pipeline, Two Syntaxes
See the same CI pipeline written in GitHub Actions YAML and Jenkinsfile — map the structural parallels.
07
🔧 Lab — First Live Pipeline
Push .github/workflows/ci.yml — watch GitHub Actions run in the Actions tab. Real pipeline, real output.
Part 1 of 5

CI vs CD vs Continuous Deployment — clear definitions

Continuous Integration

CI

Every commit triggers an automated build + test. The goal is detecting integration issues early — before they compound.

  • Developer pushes code
  • Pipeline runs: compile, lint, unit tests
  • Pass → green badge. Fail → block the merge
  • Result: always-green main branch
on: push → build + test
Continuous Delivery

CD (Delivery)

Every successful CI run produces a deployable artifact. Deployment to production is one-click / manual approval.

  • CI passes → Docker image built
  • Auto-deploys to staging environment
  • QA verifies on staging
  • Human clicks "Deploy to Production"
CI passes → staging auto-deploy
→ manual prod approval
Continuous Deployment

CD (Deployment)

Every successful CI run is automatically deployed to production. No human gate. Full automation.

  • CI passes → auto-deploy to prod
  • No manual approval gate
  • Requires excellent test coverage
  • Used by: Netflix, Amazon, Etsy
CI passes → prod deploy auto
→ feature flags for safety
ℹ Typical Organisation Progression
Most teams start at CI (automated tests on push), evolve to Continuous Delivery (staging auto-deploy, prod manual), then to Continuous Deployment once they trust their test coverage. Most enterprises stop at Continuous Delivery — human approval for production is intentional, not a failure.
The Key Difference at a Glance
CI: automated testing on every commit
Continuous Delivery: automated up to staging, manual to prod
Continuous Deployment: automated all the way to prod

In interviews: "We practise CI/CD" usually means Continuous Delivery, not full Continuous Deployment.
Part 2 of 5

Anatomy of a CI/CD Pipeline

Trigger
git push
PR opened
schedule
🔨
Build
npm install
compile
dependencies
Test
unit tests
lint
coverage
🛡
Security
SAST
dep scan
secrets
📦
Package
Docker build
push to registry
artifact
🚀
Deploy Staging
Helm upgrade
K8s apply
smoke test
🌐
Deploy Prod
manual gate
or auto
notify team
What happens at each stage
  • Trigger — git push, PR open, schedule (cron), manual. GitHub Actions: on: block. Jenkins: webhooks or poll SCM.
  • Build — install dependencies, compile. Fails here = syntax error or missing package.
  • Test — unit tests, lint, code coverage gate (e.g. fail if coverage < 80%).
  • Security — SAST (static analysis), dependency vulnerability scan (Snyk, Trivy), secret scanning.
  • Packagedocker build + push. Image tagged with commit SHA for traceability.
  • Deploy — staging first, always. Prod after approval or fully automated.
💡 Fail Fast Principle
Stages are ordered by speed: fast checks first (lint, unit tests ~1 min), slow checks last (integration tests, Docker build ~5 min). If lint fails, skip the rest — no point building an image from broken code. This keeps average feedback time under 3 minutes.
Every stage can be a gate
If any stage exits non-zero, the pipeline stops and the team is notified. This is exactly the same concept as git hooks (Day 9) — exit code 0 = pass, non-zero = fail. The principle is identical, just running in the cloud.
Part 3 of 5

CI/CD Tool Landscape — Jenkins vs GitHub Actions vs GitLab CI

🏗 Jenkins
Self-hosted · Open source · Enterprise standard
  • Hosted: You own & maintain the server
  • Config: Groovy-based Jenkinsfile
  • Plugins: 1,800+ — extreme flexibility
  • Agent model: Controller + distributed agents
  • Cost: Free, but ops overhead
  • Strength: Complex on-prem pipelines, legacy systems, heterogeneous toolchains
  • Weakness: Requires maintenance, plugin hell, steep learning curve
⚡ GitHub Actions
Cloud-hosted · YAML · GitHub-native
  • Hosted: GitHub manages runners
  • Config: YAML files in .github/workflows/
  • Marketplace: 20,000+ reusable actions
  • Triggers: push, PR, issue, schedule, manual
  • Cost: Free for public repos; minutes-based for private
  • Strength: Zero infra setup, GitHub integration, fast start
  • Weakness: Vendor lock-in, less flexible than Jenkins for complex needs
🦊 GitLab CI
Built-in platform · YAML · Complete DevOps
  • Hosted: GitLab.com or self-hosted
  • Config: .gitlab-ci.yml in repo root
  • Integration: Native registry, security scanning, DAST
  • Runners: Shared or self-hosted GitLab runners
  • Cost: Free tier; paid for advanced features
  • Strength: End-to-end DevSecOps platform, built-in security, container registry
  • Weakness: Requires using GitLab for SCM
💡 Job market reality
"CI/CD experience" in job descriptions = Jenkins for enterprises/banks/telecom, GitHub Actions for startups/SaaS/cloud-native. GitLab CI for teams using GitLab. Learning Jenkins + GitHub Actions covers 90% of job requirements. The underlying concepts (triggers, stages, artifacts) are identical across all three.
Part 4 of 5

Jenkins Architecture — Controller-Agent model

CONTROLLER UI · Config · Scheduler Jenkins Server AGENT 1 Linux VM build · test AGENT 2 Docker isolated runs AGENT 3 K8s Pod ephemeral 📄 Jenkinsfile (in your repo)
4 Jenkins Job Types
  • Freestyle — GUI-based, legacy. Avoid for new pipelines.
  • Pipeline — Jenkinsfile in repo. Recommended. Code-based.
  • Multibranch — Auto-discovers all branches. Creates a job per branch automatically.
  • Organisation Folder — Auto-discovers all repos in a GitHub org.
Jenkinsfile — Declarative
pipeline {
    agent { label 'linux' }   // which agent to run on

    environment {
        NODE_ENV = 'test'
        APP_PORT = '3000'
    }

    triggers {
        githubPush()               // webhook from GitHub
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm       // clone repo
            }
        }
        stage('Install') {
            steps {
                sh 'npm ci'
            }
        }
        stage('Test') {
            steps {
                sh 'npm test'
            }
            post {
                always {
                    junit '**/test-results/*.xml'
                }
            }
        }
        stage('Build Docker') {
            steps {
                sh 'docker build -t myapp:${BUILD_NUMBER} .'
            }
        }
    }

    post {
        success { slackSend '✅ Build passed' }
        failure { slackSend '❌ Build failed' }
    }
}
Jenkins Setup

Installing Jenkins — 3 methods, Docker is easiest

Method 1 — Docker ⭐ Recommended for learning
# === Run Jenkins in Docker (fastest start) ===
docker run -d \
  --name jenkins \
  -p 8080:8080 \
  -p 50000:50000 \
  -v jenkins_home:/var/jenkins_home \
  jenkins/jenkins:lts-jdk17

# Jenkins UI → http://localhost:8080

# === Get the initial admin password ===
docker exec jenkins \
  cat /var/jenkins_home/secrets/initialAdminPassword
# Copy this → paste in browser Unlock page

# === Stop / Start ===
docker stop jenkins
docker start jenkins
# Data persists in 'jenkins_home' volume
Method 2 — Linux Package (Ubuntu/Debian)
# Requires Java 17+
sudo apt update
sudo apt install -y fontconfig openjdk-17-jre

# Add Jenkins repo key + source
sudo wget -O /usr/share/keyrings/jenkins-keyring.asc \
  https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key
echo "deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]" \
  "https://pkg.jenkins.io/debian-stable binary/" \
  | sudo tee /etc/apt/sources.list.d/jenkins.list > /dev/null

sudo apt update && sudo apt install -y jenkins

# Start + enable
sudo systemctl enable --now jenkins
sudo systemctl status jenkins

# Get unlock password
sudo cat /var/lib/jenkins/secrets/initialAdminPassword

# UI → http://SERVER_IP:8080
Method 3 — Windows (WAR / Installer)
# Option A: Windows Installer (.msi)
# 1. Download from jenkins.io → LTS .msi
# 2. Run installer → installs as Windows Service
# 3. Opens browser at http://localhost:8080
# Password: C:\ProgramData\Jenkins\secrets\initialAdminPassword

# Option B: WAR file (any OS with Java)
java -jar jenkins.war --httpPort=8080
# Data stored in ~/.jenkins/
# Password: ~/.jenkins/secrets/initialAdminPassword

# Option C: WSL2 on Windows (recommended)
# Run the Ubuntu/Debian steps above inside WSL2
# Access at http://localhost:8080 from Windows browser
First-Run Setup Wizard — 5 Steps
  1. Unlock Jenkins — paste the initial admin password from the terminal
  2. Install Plugins — choose "Install suggested plugins" (recommended). Wait ~3 minutes for download.
  3. Create Admin User — set username, password, email. Remember these!
  4. Instance Configuration — confirm the URL (default: http://localhost:8080). Click Save.
  5. Start using Jenkins — Dashboard loads. ✅ Jenkins is ready!
💡 Essential plugins to install after setup
Go to Manage Jenkins → Plugins → Available:
NodeJS Plugin — run npm commands
GitHub Integration Plugin — webhooks
Docker Pipeline Plugin — Docker agents
Blue Ocean — modern pipeline UI (optional)
Jenkins Setup — continued

Jenkins — connect GitHub & create your first pipeline job

Step 1 — Configure NodeJS Tool
  1. Manage Jenkins → Tools
  2. Scroll to NodeJS installations → Add NodeJS
  3. Name: NodeJS-20 (exactly this — used in Jenkinsfile)
  4. Version: 20.x LTS
  5. ✅ Install automatically → Save
Step 2 — Add GitHub Credentials
  1. Manage Jenkins → Credentials → Global → Add
  2. Kind: Username with password
  3. Username: your GitHub username
  4. Password: your GitHub PAT (not your GitHub password)
  5. ID: github-credentials
  6. Save
Step 3 — Create Pipeline Job
  1. Dashboard → New Item
  2. Name: my-devops-app
  3. Type: Pipeline → OK
  4. Scroll to Pipeline section
  5. Definition: Pipeline script from SCM
  6. SCM: Git
  7. Repository URL: your GitHub repo URL
  8. Credentials: select github-credentials
  9. Branch: */main
  10. Script Path: Jenkinsfile
  11. Save → Build Now
Step 4 — GitHub Webhook (auto-trigger)
# Without webhook: Jenkins polls GitHub every N minutes
# With webhook: GitHub pushes event to Jenkins instantly

# On GitHub:
# Repo → Settings → Webhooks → Add webhook
# Payload URL:
http://YOUR_JENKINS_IP:8080/github-webhook/
# Content type: application/json
# Events: Just the push event
# Active: ✅

# For local Jenkins (not internet-accessible),
# use ngrok to expose it:
ngrok http 8080
# ngrok gives: https://abc123.ngrok.io
# Use: https://abc123.ngrok.io/github-webhook/

# In Jenkins pipeline job config:
# Build Triggers → ✅ GitHub hook trigger for GITScm polling
Jenkins vs GitHub Actions — Setup Cost
Install serverJenkins: ✋ ~20 minGHA: ✅ Zero
Configure toolsJenkins: ✋ PluginsGHA: ✅ In YAML
WebhookJenkins: ✋ ManualGHA: ✅ Automatic
CredentialsJenkins: ✋ UI setupGHA: ✅ GitHub Secrets
First pipelineJenkins: ~45 min totalGHA: ~5 min total
💡 Jenkins for learning — Docker tip
Docker install-ൽ Jenkins run ആക്കൂ — VM setup ആവശ്യം ഇല്ല. docker stop jenkins → laptop close ആക്കൂ. docker start jenkins → everything restored. Volume-ൽ data persist ആകുന്നു.
Part 5 of 5

GitHub Actions — YAML anatomy explained

GitHub Actions — .github/workflows/ci.yml
# ── Workflow name ──────────────────────
name: CI Pipeline

# ── Triggers ───────────────────────────
on:
  push:
    branches: [ main, 'feat/**' ]
  pull_request:
    branches: [ main ]

# ── Jobs ───────────────────────────────
jobs:
  build-and-test:          # Job name
    runs-on: ubuntu-latest  # Runner (agent)

    strategy:
      matrix:
        node-version: [ 18, 20 ]  # Run on both!

    steps:
      # Step 1: Clone repo
      - uses: actions/checkout@v4

      # Step 2: Setup Node.js
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: \${{ matrix.node-version }}
          cache: 'npm'

      # Step 3: Install dependencies
      - name: Install dependencies
        run: npm ci

      # Step 4: Lint
      - name: Lint
        run: npm run lint

      # Step 5: Run tests
      - name: Run tests
        run: npm test

      # Step 6: Upload coverage
      - name: Upload coverage
        uses: actions/upload-artifact@v4
        with:
          name: coverage-report
          path: coverage/
GitHub Actions Key Concepts
  • Workflow — the YAML file. One repo can have many workflows.
  • on: — what triggers this workflow (push, pull_request, schedule, workflow_dispatch)
  • Job — a unit of work that runs on one runner. Jobs run in parallel by default.
  • runs-on: — the runner OS (ubuntu-latest, windows-latest, macos-latest)
  • step — individual command within a job. Can be run: (shell) or uses: (marketplace action)
  • matrix: — run the same job with different values (Node 18 + 20 simultaneously)
  • secrets: — encrypted values (API keys, Docker credentials) stored in GitHub settings
💡 Marketplace Actions
uses: actions/checkout@v4 — someone wrote this so you don't have to. 20,000+ community actions: setup-node, setup-python, docker/build-push-action, aws-actions, azure/login. Always pin to a version tag.
Jenkins → GitHub Actions Mapping
pipeline { }jobs:
agent { }runs-on:
stage('x') { } → Job name
sh 'cmd'run: cmd
environment { }env:
Same Pipeline · Two Syntaxes

GitHub Actions vs Jenkinsfile — structural parallels

GitHub Actionsci.yml
name: CI Pipeline

on:                           # ← TRIGGER
  push:
    branches: [ main ]

jobs:                         # ← PIPELINE
  build:                      # ← JOB (= stage)
    runs-on: ubuntu-latest  # ← AGENT

    env:                      # ← ENV VARS
      NODE_ENV: test

    steps:                    # ← STEPS
      - uses: actions/checkout@v4

      - name: Install     # ← STEP
        run: npm ci       # ← SHELL CMD

      - name: Test
        run: npm test

      - name: Build
        run: docker build -t app .

  notify:                     # ← 2nd JOB
    needs: [ build ]         # ← dependency
    if: failure()
    runs-on: ubuntu-latest
    steps:
      - run: echo "Build failed!"
JenkinsfileDeclarative
// TRIGGER (configured in job, or:
// triggers { githubPush() })

pipeline {               // ← PIPELINE
    agent any             // ← AGENT

    environment {         // ← ENV VARS
        NODE_ENV = 'test'
    }

    stages {              // ← STAGES
        stage('Checkout') {// ← STAGE
            steps {       // ← STEPS
                checkout scm
            }
        }
        stage('Install') {
            steps {
                sh 'npm ci'  // ← SHELL CMD
            }
        }
        stage('Test') {
            steps {
                sh 'npm test'
            }
        }
        stage('Build') {
            steps {
                sh 'docker build -t app .'
            }
        }
    }

    post {               // ← POST (notify)
        failure {
            echo 'Build failed!'
        }
    }
}
The Mapping
GitHub ActionsJenkinsfile
jobs:pipeline { stages { } }
job namestage('name')
runs-on:agent { }
run: cmdsh 'cmd'
if: failure()post { failure { } }
needs:stage ordering
Hands-On Lab

🔧 First Live Pipeline

Push a GitHub Actions workflow → watch it run in the Actions tab → your first real CI pipeline in production

⏱ 25 minutes
my-devops-app ✓
GitHub account ✓
🔧 Lab — Steps

Build your first live CI pipeline

1
Create the workflows directory
mkdir -p .github/workflows in your my-devops-app repo. This is where all GitHub Actions YAML files live.
2
Write the CI workflow YAML
Create .github/workflows/ci.yml — triggers on push to main and feat/** branches. Runs install, lint, test.
3
Add a test script to package.json
The pipeline needs something to run. Add "test": "echo 'Tests passed' && exit 0" to package.json scripts if no test framework yet.
4
Commit and push on a feature branch
git switch -c feat/add-ci && git add . && git commit -m "ci: add github actions pipeline" && git push. Watch GitHub — the pipeline fires immediately.
5
Watch the pipeline run
GitHub repo → Actions tab → see your workflow running. Click into it to see step-by-step logs. Green ✅ = your first CI pipeline works!
6
Write the equivalent Jenkinsfile
Create Jenkinsfile in the repo root with the same stages. Note what you'd additionally need: a Jenkins server, credentials, webhook setup.
🔧 Lab — Full Code

Complete lab files

.github/workflows/ci.yml
name: CI

on:
  push:
    branches: [ main, 'feat/**' ]
  pull_request:
    branches: [ main ]

jobs:
  ci:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Setup Node.js 20
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Lint
        run: npm run lint || echo "No lint script"

      - name: Test
        run: npm test

      - name: Print success
        run: echo "✅ CI passed on $(date)"
Jenkinsfile
// Equivalent pipeline in Jenkins Declarative syntax
pipeline {
    agent any

    tools { nodejs 'NodeJS-20' }  // plugin needed

    triggers {
        githubPush()
    }

    stages {
        stage('Checkout') {
            steps { checkout scm }
        }
        stage('Install') {
            steps { sh 'npm ci' }
        }
        stage('Lint') {
            steps {
                sh 'npm run lint || echo "No lint"'
            }
        }
        stage('Test') {
            steps { sh 'npm test' }
        }
        stage('Report') {
            steps {
                echo "✅ CI passed"
            }
        }
    }
    post {
        always   { echo 'Pipeline complete' }
        success  { echo 'All green!' }
        failure  { echo 'Build failed — check logs' }
    }
}
💡 package.json scripts needed
"scripts": {
  "test": "echo 'Tests passed' && exit 0",
  "lint": "eslint . || true"
}


CI commit message: ci: add github actions pipeline
Knowledge Check

Quiz Time

3 questions · 5 minutes · CI/CD definitions, pipeline stages, and tool choice

Test your CI/CD knowledge →
QUESTION 1 OF 3
What is the key difference between Continuous Delivery and Continuous Deployment?
A
Continuous Delivery runs tests; Continuous Deployment skips tests
B
Continuous Delivery requires a manual approval gate for production; Continuous Deployment deploys automatically to production
C
Continuous Delivery is for small teams; Continuous Deployment is for large teams
D
They are identical — just different names for the same practice
QUESTION 2 OF 3
In a CI/CD pipeline, which principle determines that lint runs before integration tests?
A
Security-first — security scans must always come first
B
Alphabetical ordering of stages
C
Fail Fast — quick cheap checks first, slow expensive checks last
D
Integration tests always require root access
QUESTION 3 OF 3
A startup team with all code on GitHub, no dedicated infrastructure team, wants to start CI/CD with minimal setup effort. Which tool is the best fit?
A
Jenkins — most powerful and widely used in enterprises
B
GitHub Actions — zero infra, native GitHub integration, free for public repos
C
GitLab CI — best built-in security scanning
D
A custom shell script triggered by a cron job
Day 11 — Complete

What you learned today

🔁
CI vs CD
CI = auto test on commit. Delivery = manual prod gate. Deployment = fully automatic prod.
🏗
Pipeline Anatomy
Trigger → Build → Test → Security → Package → Deploy Staging → Deploy Prod. Fail fast ordering.
⚔️
Tool Landscape
Jenkins (enterprise, self-hosted). GitHub Actions (SaaS, zero infra). GitLab CI (GitLab platform).
First Pipeline
ci.yml live on GitHub. Actions tab shows green. Git push → pipeline trigger confirmed.
Day 11 Action Items
  1. GitHub Actions pipeline live — green ✅ in Actions tab ✓
  2. Jenkinsfile in repo root — understand the syntax ✓
  3. Commit notes/day11-cicd.md with tool comparison ✓
  4. Merge feature branch via PR ✓
Tomorrow — Day 12
GitHub Actions + Jenkins Pipelines Deep Dive

Multi-job workflows, secrets management, parallel jobs, matrix builds, reusable workflows, and a full Declarative Jenkinsfile with Docker agent.

secrets: matrix: needs: Docker agent
📌 Reference

CI/CD terms — complete glossary

TermDefinitionExample
PipelineAutomated sequence of stages triggered by a git event.github/workflows/ci.yml, Jenkinsfile
JobA unit of work that runs on one runner/agent (GitHub Actions term)build, test, deploy-staging
StageA named phase in a pipeline (Jenkins term, equivalent to job)stage('Test') { }
StepIndividual command or action within a job/stagerun: npm test, sh 'npm test'
Runner / AgentMachine that executes pipeline stepsubuntu-latest, Jenkins agent
ArtifactFile produced by a pipeline stage (Docker image, JAR, ZIP)myapp:abc123 pushed to GHCR
TriggerEvent that starts the pipelinepush, pull_request, schedule, manual
SecretEncrypted value (API key, password) injected into pipelinesecrets.DOCKER_PASSWORD
MatrixRun same job with multiple configurations in parallelNode 18 + 20 simultaneously
CachePersisted files between runs to speed up buildsnode_modules/ cached after npm install
SASTStatic Application Security Testing — code analysis without runningESLint security rules, Semgrep
GateApproval step that pauses pipeline until human confirmsProd deployment approval in CD
📌 Reference — GitHub Actions

GitHub Actions triggers & useful patterns

Common on: triggers
# Push to specific branches
on:
  push:
    branches: [ main, develop ]
    paths-ignore: [ 'docs/**', '*.md' ]

# PRs targeting main
  pull_request:
    branches: [ main ]

# Scheduled: every weekday at 8am UTC
  schedule:
    - cron: '0 8 * * 1-5'

# Manual trigger with input
  workflow_dispatch:
    inputs:
      environment:
        description: 'Deploy target'
        required: true
        default: 'staging'

# On new git tag (version release)
  push:
    tags: [ 'v*.*.*' ]

# When another workflow completes
  workflow_run:
    workflows: [ "CI" ]
    types: [ completed ]
Useful job patterns
# Skip CI with commit message
jobs:
  ci:
    if: "!contains(github.event.head_commit.message, '[skip ci]')"

# Job that needs another to complete first
  deploy:
    needs: [ ci ]
    if: github.ref == 'refs/heads/main'

# Secrets usage
    env:
      DOCKER_TOKEN: \${{ secrets.DOCKER_TOKEN }}
      BRANCH: \${{ github.ref_name }}

# Upload build artifact
      - uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

# Download in another job
      - uses: actions/download-artifact@v4
        with:
          name: dist
💡 paths-ignore = save CI minutes
Don't trigger CI for README edits. paths-ignore: ['docs/**', '*.md'] — skip the workflow when only documentation changes. Saves GitHub Actions free minutes significantly.
📌 Reference — Tool Comparison

Jenkins vs GitHub Actions — full comparison

Dimension Jenkins GitHub Actions
HostingSelf-hosted — you manage the serverGitHub-managed runners (cloud)
Pipeline configGroovy-based JenkinsfileYAML in .github/workflows/
Setup timeHours (install Jenkins, plugins, agents)Minutes (just push the YAML)
Plugins/Marketplace1,800+ plugins20,000+ marketplace actions
CostFree software, but server + ops costFree for public; 2,000 min/month free for private
SCM integrationWebhooks, pollingNative GitHub events (tight integration)
Parallel jobsParallel stages + multiple agentsJobs in parallel natively, matrix builds
SecretsJenkins Credentials StoreGitHub Secrets (repo + org + environment)
Docker supportDocker agent, docker pluginNative — all runners have Docker
Audit trailJenkins build historyGitHub Actions runs history
On-prem / air-gapped✅ Yes — self-hosted⚠️ Self-hosted runners possible
Learning curveSteep (Groovy, plugins, architecture)Moderate (YAML, action marketplace)
Best forEnterprise, on-prem, complex pipelinesSaaS, startups, OSS, cloud-native
📌 Pipeline Patterns

Common CI/CD patterns

Pattern 1: Branch-based gates

Different things happen depending on which branch was pushed:

  • feat/* → CI only (build + test)
  • main → CI + deploy to staging
  • v*.*.* tag → CI + deploy to production

if: github.ref == 'refs/heads/main'

Pattern 2: Matrix testing

Test against multiple environments simultaneously:

strategy:
  matrix:
    os: [ubuntu, windows, macos]
    node: [18, 20, 22]
# Runs 9 jobs in parallel
Pattern 3: Fan-out / Fan-in

Run multiple independent jobs in parallel, then collect results:

  • build → [unit-tests | lint | security] → deploy
  • All three middle jobs run in parallel
  • Deploy only starts when all three pass
  • GitHub Actions: needs: [unit-tests, lint, security]
Pattern 4: Environment promotion

Code flows through environments with increasing confidence:

dev → staging → prod

  • Each environment has its own secrets and config
  • Auto-deploy to dev and staging
  • Manual approval gate before production
  • GitHub: Environments + required reviewers
Pattern 5: Cache + artifact handoff
  • Cache node_modules/ — saves 30–60 sec on install per run
  • Build artifacts — build once, use in multiple deploy jobs
  • Docker layer cache — speed up image builds dramatically

cache: 'npm' in setup-node@v4 handles this automatically

💡 Rule of thumb
Keep total pipeline time under 10 minutes. If it takes longer, developers stop waiting and context-switch — feedback value is lost. Parallelize aggressively.
Week 3 Roadmap

Week 3 — CI/CD mastery path

DayTopicKey SkillLab Output
Day 11 ✅CI/CD Concepts & Tool LandscapeCI vs CD, pipeline anatomy, Jenkins vs GHAFirst GitHub Actions pipeline live
Day 12GHA + Jenkins Deep DiveSecrets, matrix, parallel jobs, Docker agentMulti-job pipeline with test matrix
Day 13Testing in CIJest, coverage thresholds, test reportsUnit tests with 80% coverage gate
Day 14Artifacts & Package ManagementDocker build + push to registry in pipelineDocker image pushed to GHCR on merge
Day 15Continuous DeploymentEnvironment promotion, approval gatesFull CD: staging auto + prod with approval
Week 2 → Week 3 Connection
Every Week 3 pipeline builds directly on Week 2:
git push (Day 6) → triggers the pipeline
Feature branch PR (Day 7) → CI runs on PR
Branch protection (Day 8) → CI required before merge
commitlint (Day 9) → commit type drives changelog
Clean rebase (Day 10) → readable pipeline history
By Day 15 you'll have:
  • ✅ Full CI pipeline (test + lint) on every PR
  • ✅ Docker image built and pushed on every merge to main
  • ✅ Auto-deploy to staging on merge
  • ✅ Manual approval gate for production
  • ✅ Jenkinsfile equivalent of the same pipeline
📌 Quick Reference

GitHub Actions — YAML structure at a glance

Full structure reference
name: Workflow Name        # shown in Actions tab

on: push / pull_request    # or full object (see S18)

env:                        # workflow-level env vars
  NODE_ENV: production

defaults:
  run:
    working-directory: ./src  # default dir for run:

jobs:
  job-name:                  # alphanumeric + dash
    runs-on: ubuntu-latest
    timeout-minutes: 15    # kill if takes too long
    needs: [ other-job ]    # dependencies
    if: condition           # conditional execution
    environment: production # GitHub Environment
    concurrency:             # prevent simultaneous runs
      group: prod-deploy
      cancel-in-progress: true
    env:                     # job-level env vars
      TOKEN: \${{ secrets.TOKEN }}
    steps:
      - name: Step description
        uses: owner/action@v1  # marketplace
        with:
          param: value
      - name: Shell step
        run: echo "hello"
        continue-on-error: true # don't fail on error
Expressions & context
  • \$\{{ github.sha }} — commit SHA
  • \$\{{ github.ref_name }} — branch/tag name
  • \$\{{ github.actor }} — who triggered
  • \$\{{ github.event_name }} — push/pr/etc
  • \$\{{ secrets.NAME }} — encrypted secret
  • \$\{{ needs.job.result }} — upstream job result
  • \$\{{ env.VAR }} — environment variable
💡 Conditional expressions
if: success() — run if all previous passed
if: failure() — run only on failure
if: always() — run regardless
if: cancelled() — run if cancelled
⚠ Never hardcode secrets in YAML
Always use \$\{{ secrets.NAME }}. Never paste tokens directly in the YAML file. They get committed to git history and become public. Store in GitHub → Settings → Secrets → Actions.