Skip to content

CI/CD Cheat Sheet

Name origin: CI/CD stands for Continuous Integration / Continuous Delivery (or Deployment). CI was popularized by Martin Fowler and Kent Beck in the early 2000s as part of Extreme Programming. The "continuous" part means every code change triggers an automated build-and-test cycle — not nightly builds. CD extends this: Continuous Delivery means every change is deployable; Continuous Deployment means every change is automatically deployed.

GitHub Actions

name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - uses: actions/setup-go@v5
      with:
        go-version: '1.22'
    - run: go test ./...
    - run: go build -o app .

  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - run: ./deploy.sh

GitLab CI

stages: [test, build, deploy]

test:
  stage: test
  image: golang:1.22
  script:
    - go test ./...

build:
  stage: build
  image: docker:24
  services: [docker:24-dind]
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

deploy:
  stage: deploy
  only: [main]
  script:
    - helm upgrade app ./chart --set image.tag=$CI_COMMIT_SHA

Pipeline Best Practices

DO:
  ✓ Pin action/image versions (SHA or tag)
  ✓ Cache dependencies (node_modules, go mod)
  ✓ Run tests before build, build before deploy
  ✓ Use branch protection + required checks
  ✓ Scan for vulnerabilities in CI (Trivy, Snyk)
  ✓ Use OIDC for cloud auth (no long-lived secrets)
  ✓ Fail fast — lint first, slow tests last

DON'T:
  ✗ Store secrets in pipeline files
  ✗ Use :latest tags in CI images
  ✗ Skip tests for "quick" deploys
  ✗ Grant admin permissions to CI service accounts
  ✗ Use self-hosted runners without hardening

Docker Build in CI

# Multi-stage build (keeps CI image small)
# Dockerfile
FROM golang:1.22 AS builder
WORKDIR /app
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o app .

FROM gcr.io/distroless/static
COPY --from=builder /app/app /app
CMD ["/app"]
# Build and push in CI
docker build -t registry.example.com/app:$SHA .
docker push registry.example.com/app:$SHA

# Or with buildx for multi-arch:
docker buildx build --platform linux/amd64,linux/arm64 \
  -t registry.example.com/app:$SHA --push .

Gotcha: actions/checkout@v4 only checks out a shallow clone by default (fetch-depth: 1). This breaks git describe, git log, and tools that need commit history. If your pipeline needs full history (e.g., semantic versioning, changelogs), add fetch-depth: 0.

Security Scanning in CI

# Container image scan
trivy image --severity HIGH,CRITICAL --exit-code 1 myapp:latest

# Filesystem scan (IaC misconfigs)
trivy fs --security-checks config .

# Secret detection
gitleaks detect --source . --verbose

# SAST
semgrep --config=auto .

Artifact Management

# GitHub Actions — upload/download
- uses: actions/upload-artifact@v4
  with:
    name: app-binary
    path: ./app

# Cache dependencies
- uses: actions/cache@v4
  with:
    path: ~/.cache/go-build
    key: go-${{ hashFiles('**/go.sum') }}

Deployment Strategies

Strategy Risk Downtime Rollback
Rolling update Low None kubectl rollout undo
Blue/Green Low None Switch LB target
Canary Lowest None Route 0% to canary
Recreate High Yes Redeploy previous

Remember: The deployment strategy risk ladder: Recreate (most risk, has downtime) > Rolling (safe default) > Blue/Green (instant rollback via LB switch) > Canary (lowest risk, gradual traffic shift). For most production services, start with rolling update and graduate to canary as your observability matures.

Common CI/CD Failures

Failure Cause Fix
Image pull failed Wrong registry/tag, auth Check image name, registry credentials
Tests pass locally, fail in CI Different env, missing deps Pin versions, match CI env locally
Deploy timeout Health check failing Check probes, resource limits
Permission denied Missing RBAC, wrong SA Check service account permissions
Cache miss Changed lockfile hash Verify cache key includes lockfile