CI/CD Pipelines
Continuous Integration and Continuous Delivery/Deployment β concepts, stages, and practical examples
What is CI/CD?
CI (Continuous Integration) β Developers merge code frequently. Each merge triggers automated builds and tests.
CD (Continuous Delivery) β Every passing build is automatically deployed to a staging environment, ready to release to production with one click.
CD (Continuous Deployment) β Goes one step further: every passing build is automatically deployed to production without human intervention.
Code Push β CI (build + test) β CD (deploy to staging) β [approve] β productionWhy CI/CD?
| Without CI/CD | With CI/CD |
|---|---|
| βIt works on my machineβ | Tested in consistent environment |
| Integration hell before releases | Integrate continuously, small changes |
| Manual, risky deployments | Automated, repeatable deployments |
| Bugs found late (in production) | Bugs caught in minutes |
| Releases every few months | Releases multiple times a day |
Pipeline Stages
A typical pipeline has these stages in order:
Source β Build β Test β Security Scan β Artifact β Deploy Staging β Smoke Test β Deploy Prod1. Source
Triggered by a git push or Pull Request. The pipeline checks out the code.
2. Build
Compile the app, install dependencies, create a binary or Docker image.
npm installnpm run builddocker build -t myapp:latest .3. Test
Run automated tests. If any fail, the pipeline stops.
npm test # unit testsnpm run test:e2e # end-to-end tests4. Security Scan (SAST/DAST)
Scan code and dependencies for known vulnerabilities.
npm audittrivy image myapp:latest5. Artifact
Push the build artifact (Docker image, JAR, ZIP) to a registry.
docker push myregistry/myapp:latest6. Deploy to Staging
Deploy the artifact to a staging/QA environment.
7. Smoke Test
Quick sanity checks against staging to confirm the app is alive.
8. Deploy to Production
After approval (or automatically), deploy to production.
GitHub Actions Example
.github/workflows/ci.yml:
name: CI/CD Pipeline
on: push: branches: [main]
jobs: build-and-test: runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20'
- name: Install dependencies run: npm ci
- name: Run tests run: npm test
- name: Build run: npm run build
deploy: needs: build-and-test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Deploy to production run: echo "Deploying..." # replace with your deploy scriptPopular CI/CD Tools
| Tool | Hosted/Self-hosted | Good For |
|---|---|---|
| GitHub Actions | Hosted (GitHub) | Most projects, free tier generous |
| GitLab CI | Both | Enterprises, all-in-one DevOps |
| Jenkins | Self-hosted | Highly customizable, legacy systems |
| CircleCI | Hosted | Fast builds, Docker-first |
| ArgoCD | Self-hosted | Kubernetes GitOps deployments |
| Tekton | Self-hosted | Kubernetes-native pipelines |
Key Concepts
Artifacts
The output of a build step stored and passed between stages. Examples: Docker image, .jar file, .zip archive.
Environment Variables & Secrets
Never hardcode credentials. Use your CI platformβs secrets manager:
# GitHub Actionsenv: DB_PASSWORD: ${{ secrets.DB_PASSWORD }}Caching
Speed up pipelines by caching dependencies:
- uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}Rollback Strategy
Always be able to go back. Common approaches:
- Blue/Green β two identical environments, switch traffic between them
- Canary β roll out to 5% of users first, then gradually increase
- Feature flags β deploy code but keep features off until ready
Best Practices
- Keep pipelines fast β aim for under 10 minutes for CI
- Fail fast β run quick checks (lint, unit tests) before slow ones (e2e, build)
- One pipeline per repo β keep pipelines close to the code
- Never commit secrets β use environment variables and secret managers
- Version your pipeline configs β theyβre code too, review them in PRs
- Notify on failure β send Slack/email alerts when pipelines break