Bootcamp
CI/CD one-day bootcamp: pipelines, caching, tests, deploys, security, observability.
CI/CD — bootcamp
EXAMPLE
# ===== 0-30 min: minimal pipeline =====
# .github/workflows/ci.yml
name: ci
on: [push, pull_request]
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: 'npm' }
- run: npm ci
- run: npm test
# Commit + push; verify it runs on GitHub Actions.
# ===== 30-60 min: branch protection =====
# Settings -> Branches -> Add branch protection rule for 'main':
# - Require pull request reviews (1+)
# - Require status checks (test job)
# - Require linear history
# - Restrict who can merge
# ===== 60-120 min: matrix + caching =====
strategy:
matrix:
node: ['18', '20', '22']
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: ${{ matrix.node }}, cache: 'npm' }
- run: npm ci
- run: npm test
# Manual cache:
- uses: actions/cache@v4
with:
path: ~/.cache/turbo
key: turbo-${{ github.sha }}
restore-keys: turbo-
# ===== 120-180 min: docker build + push =====
jobs:
build:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
push: true
tags: 'ghcr.io/${{ github.repository }}:${{ github.sha }}'
cache-from: type=gha
cache-to: type=gha,mode=max
# ===== 180-240 min: deploy with manual approval =====
jobs:
deploy:
needs: build
runs-on: ubuntu-latest
environment:
name: production
url: https://shop.example.com
steps:
- run: ./deploy.sh ${{ github.sha }}
# Settings -> Environments -> production -> Require reviewers.
# ===== 240-300 min: security =====
# SAST: Semgrep / CodeQL
# Dependency scanning: Dependabot / Snyk / OSV-Scanner
# Container scanning: Trivy
# Add Trivy step:
- uses: aquasecurity/trivy-action@master
with:
image-ref: ghcr.io/${{ github.repository }}:${{ github.sha }}
severity: 'HIGH,CRITICAL'
exit-code: '1'
# Secret scanning: gitleaks
- uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# ===== 300-360 min: observability =====
# Output JUnit results:
- run: npm test -- --reporter=junit --outputFile=junit.xml
- uses: actions/upload-artifact@v4
if: always()
with: { name: junit, path: junit.xml }
# Coverage to Codecov:
- uses: codecov/codecov-action@v4
with: { files: ./coverage/lcov.info }
# Build metrics:
# Use github/buildx-imagetools or third-party telemetry to track build durations + failure rates.
# ===== 360-420 min: rollouts =====
# Canary or staged rollout via deploy script:
- run: ./deploy.sh canary 10 # 10% traffic
- name: Health check
run: sleep 60 && ./health-check.sh https://shop.example.com
- run: ./deploy.sh canary 100 # promote
# Or use Argo Rollouts, Flagger, AWS CodeDeploy.
# ===== 420-480 min: GitOps =====
# Argo CD or Flux watches a git repo with manifests; reconciles cluster state.
# Workflow:
# 1. CI builds + pushes image
# 2. Updates manifest (image tag) in a deployment repo
# 3. Argo CD detects the change, applies to cluster
# ===== Patterns to internalise =====
# - Cheap stages first (lint, typecheck, test, build, deploy)
# - Required status checks on default branch
# - Cache deps; never cache build outputs
# - Feature flags decouple deploy + release
# - SAST + DAST + dependency + container scanning in CI
# - Manual approval gates on prod; auto on staging
# - GitOps for cluster state
# ===== Pitfalls =====
# - Slow pipelines (> 20 min) -> people batch commits
# - 'latest' tags in production
# - Secrets in plain YAML
# - No rollback rehearsed
# - Coverage gates without quality (chase numbers, miss bugs)
Why it matters
A one-day CI/CD bootcamp: minimal workflow, branch protection, matrix + caching, docker build + push, deploy with approval, security scans, observability, rollouts, GitOps. The shape works across GitHub Actions / GitLab / Buildkite / CircleCI; the discipline is universal.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Discussion
Loading…