Skip to content

CI/CD — Basics

  • CI (Continuous Integration) — every commit triggers build + test on shared branch.
  • CD = Continuous Delivery (always shippable, manual deploy) or Deployment (auto deploy to prod on green).

Goal: small frequent changes, fast feedback, low-risk releases.

  1. Lint — formatters, eslint, hadolint, terraform fmt, etc.
  2. Type check / static analysis — tsc, mypy, semgrep.
  3. Unit tests — fast, isolated.
  4. Build — compile, bundle, container image.
  5. Integration tests — DB-backed, contract tests, API tests.
  6. Security scans — SCA, SAST, container scan, IaC scan.
  7. Push artifact — to registry (with version + digest).
  8. Deploy to env — dev → staging → prod (auto or gated).
  9. Smoke tests — post-deploy verification.
  10. Rollback if checks fail.
  • GitHub Actions — popular, integrated with GH, good ecosystem.
  • GitLab CI — built into GitLab, runners self-hosted possible.
  • CircleCI, Jenkins (mature, plugins-heavy), Buildkite (self-hosted runners), TeamCity, Azure Pipelines, AWS CodePipeline, Drone, Argo Workflows.
  • Recreate — kill all old, deploy new. Outage; simple.
  • Rolling — replace pods/instances incrementally. K8s default.
  • Blue/Green — two full envs, switch LB. Easy rollback; cost.
  • Canary — release to small % of traffic, observe, ramp up.
  • Feature flag — code shipped but gated; toggle on/off without deploy.
  • Shadow / mirroring — duplicate traffic to new version, compare; no user impact.
  • Dev — broken often; fast iteration.
  • Staging / pre-prod — prod-like, integration testing.
  • Prod — real users.
  • Ephemeral / preview — per-PR environment for review.
  • Versioned + immutable. Tagged with commit SHA + semver.
  • Stored in registry (Docker), package registry (npm, PyPI), or S3.
  • Same artifact promoted across envs (don’t rebuild per env).
  • SBOM + signature (cosign) for supply chain trust.
  • Trunk-based — short-lived branches → main; feature flags. Recommended for high-velocity teams.
  • GitFlow — develop / release / hotfix branches. Heavier process; mature releases.
  • GitHub Flow — main + feature branches + PR.
  • Dep cachenode_modules, pip wheels, Maven, Cargo.
  • Build cache — Docker BuildKit, sccache, ccache, Turborepo, Nx, Bazel.
  • Cache keys based on lockfile checksums + OS + arch.
  • Provider-native (GH Actions secrets, GitLab CI variables).
  • Environment-scoped + protected.
  • Use OIDC to assume cloud roles instead of long-lived keys.
  • Mask in logs.
  • Deployment Frequency — daily+ for elite.
  • Lead Time for Changes — commit → prod, hours best.
  • Change Failure Rate — < 15%.
  • MTTR — minutes-hours for elite.
name: ci
on:
push: { branches: [main] }
pull_request: {}
permissions: { contents: read, id-token: write }
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm i --frozen-lockfile
- run: pnpm lint && pnpm typecheck && pnpm test
build:
needs: test
runs-on: ubuntu-latest
outputs: { image: ${{ steps.push.outputs.image }} }
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: push
uses: docker/build-push-action@v6
with:
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
deploy:
needs: build
runs-on: ubuntu-latest
environment: prod
steps:
- uses: actions/checkout@v4
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE }}
aws-region: eu-west-1
- run: ./deploy.sh ${{ github.sha }}