Chương 04 · Foundation

CI/CD Fundamentals

Continuous Integration, Continuous Delivery, Continuous Deployment — 3 thuật ngữ thường nhầm. Pipeline as Code: GitHub Actions, GitLab CI, Jenkins. Build → Test → Package → Deploy stages. Caching, parallelization, artifact registry, security gate. Đây là tim mạch của DevOps automation.

1. Continuous Integration / Delivery / Deployment — Phân biệt

3 từ này hay bị dùng lẫn lộn. Hiểu cho đúng:

1.1. Continuous Integration (CI)

Định nghĩa: dev merge code vào shared branch (main/develop) thường xuyên (≥ 1 lần/ngày), mỗi lần merge tự động build + test.

Mục tiêu: phát hiện integration bug sớm. Trước CI, dev làm 2 tuần trên branch riêng → merge → vỡ tan. Với CI, merge thường xuyên → conflict nhỏ, dễ giải.

"Continuous" theo nghĩa thường xuyên, không phải liên tục 24/7.

1.2. Continuous Delivery (CD₁)

Định nghĩa: mỗi commit pass CI sẽ được build thành artifact "ready to deploy", chỉ cần ấn nút (manual approval) là production.

Mục tiêu: deploy là quyết định business, không phải vấn đề kỹ thuật. Tech team luôn sẵn sàng deploy bất cứ lúc nào.

1.3. Continuous Deployment (CD₂)

Định nghĩa: như Continuous Delivery + bỏ luôn manual approval. Mỗi commit pass tất cả test → tự deploy production.

Đây là trạng thái cao nhất. Yêu cầu: test cực mạnh, monitoring tốt, feature flag, rollback automated.

1.4. So sánh trực quan

┌─ CI ──┐ ┌─ CD₁ ───┐ ┌── CD₂ ──┐ │ │ │ │ │ │ Code → Commit ───→ Build → Test → Stage → [Manual] → Production ↑ └── CD₂ skip this
Mô hìnhĐặc trưngAi làm được
CI only Build + test mỗi commit; deploy thủ công sau Hầu hết team đều làm được
CI + Continuous Delivery Artifact luôn deploy-ready, ấn nút deploy Team có testing tốt, monitoring
CI + Continuous Deployment Tự động deploy mỗi commit Elite team — Netflix, Etsy, Stripe

Khi ai đó nói "chúng tôi có CI/CD", thường là CI + Continuous Delivery. Continuous Deployment cần kỷ luật rất cao.

2. Vì sao CI/CD? Lợi ích cụ thể

2.1. Giảm risk per deploy

Deploy nhỏ < deploy lớn:

  • Deploy 100 commit → khó debug khi fail.
  • Deploy 1 commit → rollback dễ, biết ngay commit nào sai.

2.2. Feedback nhanh

  • Bug được phát hiện trong vài phút (CI fail) thay vì vài tuần.
  • Cost fix tăng exponentially theo time-to-detect.

2.3. Confidence cao hơn

  • Test tự động chạy mỗi PR → không sợ "tôi đã test chưa?".
  • Pipeline pass = code đã qua N gate (lint, test, security, performance).

2.4. Tốc độ phát triển

  • Không phải đợi QA test thủ công 2 tuần.
  • Không có "release week" cuối tháng.
  • Feature đi tới user nhanh hơn.

2.5. Business case

DORA report: Elite (CI/CD đầy đủ) team:

  • Deploy thường xuyên hơn 200×.
  • Lead time ngắn hơn 2604×.
  • MTTR ngắn hơn 2604×.
  • Change failure rate thấp hơn 7×.

Tóm lại: CI/CD vừa nhanh hơn vừa ổn hơn. Không phải trade-off.

3. Anatomy of a Pipeline — 7 stage chuẩn

① Trigger
② Lint
③ Build
④ Test
⑤ Scan
⑥ Package
⑦ Deploy

3.1. Trigger

  • Push — push lên branch.
  • Pull Request — mở/update PR.
  • Schedule — cron (vd nightly build).
  • Manual — workflow_dispatch.
  • External — webhook từ system khác.
  • Tag — tag mới (release).

3.2. Lint & Format

Static analysis trước cả build — fast fail nếu code không follow style/quality:

  • JS/TS: ESLint, Prettier.
  • Python: flake8, ruff, black, mypy.
  • Go: gofmt, golangci-lint.
  • Java: Checkstyle, SpotBugs.
  • Terraform: terraform fmt + tflint.

3.3. Build

Compile/transpile/bundle code:

  • JS: webpack, vite, esbuild, rollup.
  • TypeScript: tsc.
  • Java: Maven (mvn package), Gradle (gradle build).
  • Go: go build.
  • Container: docker build (đến chương 5).

3.4. Test

Theo Test Pyramid (mục 9):

  • Unit test — nhiều, nhanh (giây). Jest, JUnit, pytest.
  • Integration test — vừa phải, vài giây-phút. testcontainers, mock external API.
  • E2E test — ít, chậm (phút). Playwright, Cypress, Selenium.

3.5. Security Scan (DevSecOps)

  • SAST — Static App Security Testing (analyze code). Semgrep, SonarQube, Snyk Code.
  • SCA — Software Composition Analysis (dependency vuln). npm audit, Snyk, Dependabot.
  • Secret scan — gitleaks, trufflehog.
  • Container scan — Trivy, Snyk Container.
  • IaC scan — tfsec, Checkov, KICS.

3.6. Package

  • Container image → push registry (ECR, GAR, ACR, GHCR, Docker Hub).
  • JAR/WAR → Artifactory, Nexus, Maven Central.
  • npm package → npm registry, GitHub Packages.
  • Helm chart → ChartMuseum, OCI registry.
  • Binary → GitHub Releases, S3, GCS.

3.7. Deploy

Đẩy artifact vào environment:

  • Push-based: pipeline gọi kubectl apply, terraform apply, aws deploy.
  • Pull-based (GitOps): pipeline update Git repo → ArgoCD/Flux phát hiện và sync.

Strategies (mục 10): rolling, blue-green, canary, recreate.

4. So sánh các CI/CD tools 2026

ToolTypeProsCons
GitHub Actions SaaS (or self-hosted runner) Tích hợp GitHub sâu, marketplace lớn, free generous Vendor lock-in (GitHub), runner private đắt
GitLab CI SaaS + Self-hosted All-in-one (Git + CI + Container reg), generous free tier YAML phức tạp khi pipeline lớn
Jenkins Self-hosted Plugin ecosystem lớn nhất, customizable UX cũ, maintain plugin đau, chậm
CircleCI SaaS Fast, parallelism tốt Pricing
BuildKite SaaS UI + self-host runner Hybrid: data ở firewall của bạn, control plane SaaS Setup khó hơn
Tekton K8s-native Cloud-native, declarative Verbose YAML, overhead K8s
ArgoCD / Flux K8s GitOps CD Declarative deploy, drift detection CD only — cần CI tool kết hợp
AWS CodePipeline AWS-native Tích hợp AWS sâu, pay per use Lock-in AWS, UX hạn chế

4.1. Pricing (rough, 2026)

  • GitHub Actions: free 2000 phút/tháng public + 2000 phút/tháng private (free tier). Linux runner $0.008/phút.
  • GitLab CI: free 400 phút compute/tháng (free), $19/user/month for premium.
  • CircleCI: free 6000 phút/tháng (Linux Medium), $15/user/month for Performance.
  • Self-host (Jenkins, GitLab Runner, GHA self-hosted): infrastructure cost only.

4.2. Khi nào chọn cái nào?

  • Đã dùng GitHub → GitHub Actions (zero friction).
  • Đã dùng GitLab → GitLab CI.
  • Cần all-in-one self-host → GitLab self-host hoặc Jenkins.
  • K8s heavy → ArgoCD/Flux + Tekton hoặc GHA.
  • Enterprise legacy → Jenkins (vẫn phổ biến).

5. GitHub Actions — Pipeline đầu tiên của bạn

Trong giáo trình này dùng GitHub Actions làm chính. Lý do: free, dễ học, syntax declarative gọn.

5.1. Concept

  • Workflow — file YAML ở .github/workflows/.
  • Event — trigger workflow (push, pull_request, schedule, workflow_dispatch).
  • Job — group các step, chạy trên runner.
  • Step — đơn vị nhỏ nhất: chạy 1 command hoặc 1 action.
  • Action — reusable step (vd actions/checkout@v4).
  • Runner — máy chạy job (ubuntu-latest, windows-latest, macos-latest, hoặc self-hosted).

5.2. Workflow đơn giản

# .github/workflows/ci.yml
name: CI

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

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

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

      - name: Install
        run: npm ci

      - name: Lint
        run: npm run lint

      - name: Test
        run: npm test

5.3. Multi-job với dependencies

name: CI/CD

on: [push]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: echo "Linting..."

  test:
    runs-on: ubuntu-latest
    needs: lint                          # chạy sau lint
    strategy:
      matrix:
        node: [18, 20, 22]               # test 3 version Node parallel
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
      - run: npm ci && npm test

  build-image:
    runs-on: ubuntu-latest
    needs: test                          # chạy sau test
    if: github.ref == 'refs/heads/main'  # chỉ trên main
    steps:
      - uses: actions/checkout@v4
      - name: Build Docker image
        run: docker build -t myapp:${{ github.sha }} .

  deploy:
    runs-on: ubuntu-latest
    needs: build-image
    environment: production              # require approval (config trong settings)
    steps:
      - run: echo "Deploying..."

5.4. Secrets & Environment Variables

jobs:
  deploy:
    runs-on: ubuntu-latest
    env:
      NODE_ENV: production
      REGION: us-east-1
    steps:
      - name: Login to AWS
        env:
          AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
          AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        run: aws sts get-caller-identity

      # Hoặc dùng OIDC (preferred — không cần long-lived secret)
      - name: Configure AWS credentials via OIDC
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: arn:aws:iam::123456789012:role/gha-deploy
          aws-region: us-east-1
OIDC tốt hơn long-lived secret GitHub Actions OIDC: GitHub issue short-lived token, AWS verify trust policy → assume role. Không cần lưu AWS_ACCESS_KEY_ID/SECRET trong GitHub secrets. Cùng cơ chế cho GCP, Azure, HashiCorp Vault.

5.5. Reusable workflow & composite action

# .github/workflows/reusable-test.yml
name: Reusable Test

on:
  workflow_call:
    inputs:
      node-version:
        type: string
        default: '20'

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci && npm test

# Sử dụng:
# .github/workflows/main.yml
jobs:
  test:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: '22'

6. GitLab CI — All-in-one

GitLab CI là tính năng built-in của GitLab. Khái niệm tương tự GHA nhưng tổ chức khác.

# .gitlab-ci.yml
stages:
  - lint
  - test
  - build
  - deploy

variables:
  NODE_VERSION: "20"

lint:
  stage: lint
  image: node:${NODE_VERSION}
  script:
    - npm ci
    - npm run lint
  cache:
    key: ${CI_COMMIT_REF_SLUG}
    paths:
      - node_modules/

test:
  stage: test
  image: node:${NODE_VERSION}
  parallel:
    matrix:
      - NODE_VERSION: ["18", "20", "22"]
  services:
    - postgres:15                          # service container cho integration test
  variables:
    POSTGRES_DB: testdb
    DATABASE_URL: postgres://postgres@postgres:5432/testdb
  script:
    - npm ci
    - npm test
  coverage: '/Lines\s*:\s*(\d+\.\d+)/'

build-image:
  stage: build
  image: docker:24
  services:
    - docker:24-dind                       # Docker-in-Docker
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
  script:
    - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .
    - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

deploy-prod:
  stage: deploy
  rules:
    - if: $CI_COMMIT_TAG                   # chỉ deploy khi tag
  environment:
    name: production
    url: https://app.example.com
  when: manual                              # cần approval
  script:
    - kubectl set image deployment/myapp myapp=$CI_REGISTRY_IMAGE:$CI_COMMIT_TAG

Đặc trưng GitLab CI:

  • stages — global, chạy tuần tự; jobs trong stage chạy parallel.
  • services — sidecar container (DB, Redis) cho test.
  • rules / only / except — điều kiện chạy job.
  • environments — track deployment per env, có URL.
  • artifacts — pass file giữa stages.

7. Jenkins — Veteran của CI

Jenkins (2011, fork của Hudson) là CI tool old guard. Vẫn phổ biến enterprise. Ưu thế: 1800+ plugin.

7.1. Jenkinsfile — Pipeline as Code

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    environment {
        NODE_VERSION = '20'
        REGISTRY = 'ghcr.io/myorg/myapp'
    }

    options {
        timeout(time: 30, unit: 'MINUTES')
        buildDiscarder(logRotator(numToKeepStr: '10'))
    }

    stages {
        stage('Checkout') {
            steps {
                checkout scm
            }
        }

        stage('Lint & Test') {
            parallel {
                stage('Lint') {
                    steps {
                        sh 'npm ci && npm run lint'
                    }
                }
                stage('Unit Test') {
                    steps {
                        sh 'npm test'
                    }
                    post {
                        always {
                            junit 'reports/junit.xml'
                        }
                    }
                }
            }
        }

        stage('Build Image') {
            when { branch 'main' }
            steps {
                sh "docker build -t ${REGISTRY}:${env.BUILD_NUMBER} ."
                withCredentials([usernamePassword(
                    credentialsId: 'github-registry',
                    usernameVariable: 'USER', passwordVariable: 'PASS')]) {
                    sh "docker login ghcr.io -u ${USER} -p ${PASS}"
                    sh "docker push ${REGISTRY}:${env.BUILD_NUMBER}"
                }
            }
        }

        stage('Deploy Prod') {
            when { branch 'main' }
            steps {
                input message: 'Deploy to prod?', ok: 'Yes'
                sh "kubectl set image deployment/myapp myapp=${REGISTRY}:${env.BUILD_NUMBER}"
            }
        }
    }

    post {
        failure {
            slackSend channel: '#alerts', message: "Build failed: ${env.BUILD_URL}"
        }
        success {
            echo 'Build successful'
        }
    }
}

7.2. Jenkins pros/cons

Pros

  • Plugin cho mọi thứ
  • Self-host, full control
  • Mature, enterprise-tested
  • Free

Cons

  • UX cũ, chậm
  • Plugin breakage thường xuyên
  • Master node SPOF
  • Maintain đau (Java OOM, plugin update)
  • Groovy DSL khó debug

Modern team thường chuyển sang GitHub Actions / GitLab CI. Jenkins vẫn solid nếu cần plugin niche hoặc air-gapped.

8. Cache & Artifact — tăng tốc pipeline

8.1. Cache

Cache dependencies giữa job runs để không phải npm install mỗi lần (mất 1-3 phút).

# GitHub Actions
- name: Setup Node with cache
  uses: actions/setup-node@v4
  with:
    node-version: '20'
    cache: 'npm'                           # auto cache node_modules

# Hoặc explicit:
- uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      node_modules
    key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
    restore-keys: |
      ${{ runner.os }}-node-

8.2. Artifact

Artifact = file output của job, dùng để pass giữa job hoặc download từ UI.

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm run build
      - name: Upload build artifact
        uses: actions/upload-artifact@v4
        with:
          name: dist
          path: dist/
          retention-days: 7

  deploy:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download build artifact
        uses: actions/download-artifact@v4
        with:
          name: dist
          path: dist/
      - run: aws s3 sync dist/ s3://my-bucket/

8.3. Container layer cache

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

- name: Build & push
  uses: docker/build-push-action@v5
  with:
    context: .
    push: true
    tags: ghcr.io/me/myapp:${{ github.sha }}
    cache-from: type=gha                   # GitHub Actions cache backend
    cache-to: type=gha,mode=max

8.4. Parallelization

# Matrix strategy
strategy:
  matrix:
    os: [ubuntu-latest, macos-latest]
    node: [18, 20, 22]
    # → 6 jobs parallel

# Test sharding (split test thành N nhóm)
- run: npm test -- --shard=${{ matrix.shard }}/4
  strategy:
    matrix:
      shard: [1, 2, 3, 4]

Mục tiêu: pipeline < 10 phút. Pipeline chậm → dev cuối ngày commit dồn → CI quá tải → vòng luẩn quẩn.

9. Test Pyramid trong CI

Mike Cohn (2009) đề xuất "Test Pyramid":

╱╲ ← Manual / Exploratory ╱ ╲ (rất ít) ╱─E2E╲ ← End-to-end tests ╱──────╲ (browser, full stack) ╱ ╲ (5-10%) ╱ Integ. ╲ ← Integration tests ╱────────────╲ (DB, API real) ╱ ╲ (15-25%) ╱ Unit ╲ ← Unit tests ╱────────────────────╲ (fast, isolated) (70-80%)

9.1. Mỗi level

LevelĐo gìSpeedStabilityCost
Unit1 function/class isolatedmsHighLow
IntegrationModule tương tác (DB, API)secondsMediumMedium
E2EUser journey fullminutesLow (flaky)High
ManualUX, exploratoryhoursHighest

9.2. Anti-patterns

  • Ice Cream Cone — pyramid ngược: nhiều E2E, ít unit. Pipeline chậm 30+ phút, flaky.
  • Cupcake — chỉ có manual test. Không CI thật.
  • Hourglass — nhiều unit + nhiều E2E, ít integration. Miss bug ở seam giữa modules.

9.3. Test trong pipeline

jobs:
  test:
    runs-on: ubuntu-latest
    services:
      postgres:                            # service container
        image: postgres:15
        env:
          POSTGRES_PASSWORD: test
        options: --health-cmd pg_isready
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci

      # Unit (fast, không cần infrastructure)
      - run: npm run test:unit

      # Integration (cần Postgres)
      - run: npm run test:integration
        env:
          DATABASE_URL: postgres://postgres:test@localhost/testdb

      # E2E
      - run: npm run test:e2e

      # Coverage report
      - uses: codecov/codecov-action@v4
        with:
          file: ./coverage/lcov.info

9.4. Chống flaky test

  • Retry: jest --retry=2, Playwright retries: 2.
  • Parallel only true unit; integration/E2E phải isolate (separate DB instance).
  • Quarantine: skip flaky test với .skip() + ticket fix sau.
  • Detect flake: chạy test 100 lần, bất kỳ test nào ≥ 1 fail là flaky.

10. Deployment Strategies

10.1. Recreate

Stop hết v1, start v2. Đơn giản nhưng có downtime.

v1 ●●●●● → STOP → ○○○○○ → START → v2 ●●●●● ↑ downtime

OK cho dev environment, không OK cho prod.

10.2. Rolling Update

Thay từng instance v1 bằng v2. Default của K8s Deployment.

v1 v1 v1 v1 v1 v1 v1 v1 v1 v2 ← thay 1 instance v1 v1 v1 v2 v2 v1 v1 v2 v2 v2 v1 v2 v2 v2 v2 v2 v2 v2 v2 v2

Không downtime nhưng v1 và v2 chạy song song trong vài phút (cần backward compat).

10.3. Blue-Green

Có 2 environment giống hệt nhau (Blue = v1 prod, Green = v2 idle). Deploy v2 lên Green, switch load balancer → Green = prod, Blue = idle.

┌─→ Blue (v1) ●●●●● ← prod LB / DNS ──────┤ └─→ Green (v2) ○○○○○ ← deploy v2 here After switch: ┌─→ Blue (v1) ○○○○○ ← idle (rollback ready) LB / DNS ──────┤ └─→ Green (v2) ●●●●● ← prod NOW

Pros: instant switch, instant rollback. Cons: cần 2× resource.

10.4. Canary

Deploy v2 chỉ cho 5% user. Monitor metric. Nếu OK, mở rộng dần (5% → 20% → 50% → 100%).

Hour 0: 100% v1 Hour 1: 95% v1, 5% v2 (canary) ← monitor metrics Hour 2: 80% v1, 20% v2 Hour 4: 50/50 Hour 8: 10% v1, 90% v2 Hour 12: 100% v2

Pros: rủi ro thấp nhất, test với traffic thật. Cons: phức tạp (cần traffic split, monitoring).

Tools: Argo Rollouts, Flagger (Flux), Istio, Linkerd.

10.5. Feature Flag (xem chương 14)

Deploy code nhưng không bật feature. Bật cho 5% user, mở rộng. Thực ra là canary ở mức code, không phải instance.

10.6. So sánh

StrategyDowntimeResource costRiskRollback
RecreateYesMedSlow (re-deploy)
RollingNo~1× (1 instance extra)MedRoll back rolling
Blue-GreenNoLowInstant (switch back)
CanaryNo1.05×LowestQuick (stop expanding)

11. Pipeline Security — Tránh bị hack qua CI

CI/CD là nơi quyền cao tập trung (production deploy key, cloud admin). Nếu pipeline bị compromise = full RCE prod.

11.1. Threats

  • Malicious dependency — npm package chứa backdoor (vd event-stream 2018).
  • Compromised runner — runner public chia sẻ với job khác → leak secret.
  • PR injection — fork PR có script chạy trên runner host.
  • Secret leak — print secret vào log, push branch chứa key.

11.2. Best practices

  • Least privilege: pipeline có quyền vừa đủ. Production deploy có review gate.
  • OIDC / short-lived token: thay AWS_ACCESS_KEY long-lived bằng OIDC assume role 15 phút.
  • Secret manager: dùng GitHub Secrets / Vault, không hard-code trong YAML.
  • Pin actions theo SHA:
    # ❌ Tag (có thể thay đổi)
    - uses: actions/checkout@v4
    
    # ✓ SHA (immutable)
    - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11  # v4.1.1
  • Fork PR isolation: pull_request_target không nên dùng tùy tiện.
  • Self-host runner cho job sensitive: branch ephemeral, fresh instance mỗi job.
  • Mask secret trong log: GHA tự mask, nhưng coi chừng secret base64-encode/JSON-encode bypass mask.
  • SBOM + signing: ký artifact bằng cosign (chương 12 DevSecOps).
  • Branch protection: require PR approve, required status check.

11.3. Tools

  • StepSecurity Harden-Runner — egress firewall cho runner.
  • chainguard-images — base image distroless, signed.
  • cosign — sign container image.
  • Sigstore — supply chain verification.
  • SLSA — Supply chain Levels for Software Artifacts framework.

12. Bài tập

  1. First pipeline: tạo GitHub repo Node.js, viết workflow CI: install + lint + test trên mỗi push/PR. Verify pipeline chạy < 3 phút.
  2. Matrix testing: extend pipeline để test trên Node 18/20/22 và Ubuntu/macOS/Windows.
  3. Cache: thêm npm cache. Đo thời gian: lần 1 (no cache) vs lần 2+ (with cache).
  4. Service container: thêm integration test với Postgres service. Test query insert/select.
  5. Secret management: setup GitHub Secrets. Pipeline deploy lên S3 dùng AWS credential. Sau đó migrate sang OIDC.
  6. Artifact: build job tạo dist/, deploy job download dist/ và push lên hosting.
  7. Branch protection: setup main branch protection: require CI pass, ≥ 1 approver, no force push. Test thử push thẳng.
  8. Reusable workflow: extract test job thành reusable workflow. Dùng từ 2 repo khác nhau.
  9. Canary deploy simulation: dùng Argo Rollouts / Flagger trên minikube. Deploy v2 với canary 20%, monitor, mở rộng dần.
  10. Pipeline security:
    • Pin tất cả actions theo SHA.
    • Add gitleaks scan để detect secret.
    • Add Trivy scan cho Docker image.
    • Setup harden-runner để firewall egress.
  11. Pipeline analysis: pipeline hiện tại 25 phút. Phân tích: mỗi step bao lâu? Stage nào parallelize được? Áp dụng và đo lại.
  12. Compare: implement cùng pipeline trên GitHub Actions, GitLab CI, Jenkins. So sánh syntax, performance, ergonomics.

13. Quiz

Quiz cuối Chương 4

Continuous Delivery KHÁC Continuous Deployment ở:

  • CD₁ chạy nhanh hơn
  • CD₂ chỉ cho enterprise
  • CD₁ có manual approval trước prod; CD₂ tự động deploy mỗi commit pass test
  • CD₂ không cần CI
CI: build + test mỗi commit. Continuous Delivery (CD₁): mọi commit tạo artifact deploy-ready, cần ấn nút deploy. Continuous Deployment (CD₂): bỏ manual approval, tự động prod. Đa số team dừng ở CI + Continuous Delivery. Continuous Deployment yêu cầu testing/monitoring/feature-flag rất tốt.

DORA report 2024 chỉ ra rằng deploy frequency và stability:

  • Đối nghịch — deploy nhiều = lỗi nhiều
  • Cùng cải thiện — Elite team deploy nhanh hơn 200× và lỗi ÍT HƠN 7×
  • Không liên quan
  • Chỉ phụ thuộc tool
Phát hiện quan trọng nhất của DORA. Trước đây niềm tin: "deploy chậm để ổn". Thực ra: deploy nhỏ thường xuyên = lỗi ít hơn vì (1) thay đổi nhỏ dễ debug, (2) team có muscle memory deploy, (3) automation đầu tư đầy đủ. Speed và stability bổ trợ nhau, không trade-off.

Test Pyramid khuyến nghị tỷ lệ test:

  • Nhiều E2E, ít unit
  • Chỉ unit
  • Bằng nhau
  • Nhiều unit (70-80%), vừa integration (15-25%), ít E2E (5-10%)
Pyramid: nhiều unit (nhanh, ổn định, rẻ) ở dưới đáy; ít E2E (chậm, flaky, đắt) ở đỉnh. Anti-pattern "Ice Cream Cone" (ngược pyramid) là lý do nhiều team có CI 30+ phút và CI flaky. Mỗi level test khác nhau, complement nhau.

OIDC trong GitHub Actions deploy AWS tốt hơn AWS_ACCESS_KEY long-lived ở điểm nào?

  • Token short-lived (15 phút), không cần lưu credential trong GitHub Secrets, có thể trace qua CloudTrail rõ
  • Nhanh hơn
  • Free
  • Không cần config
OIDC: GitHub issue ID token signed → AWS verify trust policy (giới hạn repo + branch + workflow) → assume IAM role → trả STS credential 15 phút. Nếu GitHub bị hack, attacker không có long-lived AWS key. Best practice 2024+ — Microsoft, Google support tương tự cho Azure, GCP.

Blue-Green deploy có ưu điểm gì so với Rolling Update?

  • Tiết kiệm resource hơn
  • Cài đơn giản hơn
  • Instant rollback (switch back load balancer); không có v1+v2 chạy song song trong production cùng lúc
  • Không cần load balancer
Rolling: trong vài phút deploy, có cả v1 và v2 chạy → cần backward compat. Blue-Green: switch nhanh, full v1 hoặc full v2. Cost: 2× resource. Best for: app khó backward compat (vd schema DB thay đổi, format API thay đổi). Worst for: stateful app có in-flight session.

Pin GitHub Action theo SHA thay vì tag (vd v4) là vì:

  • Nhanh hơn
  • Dễ đọc hơn
  • Chỉ là style
  • Tag có thể bị move (maintainer push khác lên cùng tag) → SHA immutable, supply chain attack khó hơn
Tag v4 hoặc v4.1.1 có thể bị maintainer (hoặc attacker compromise) thay đổi để trỏ commit khác. SHA cố định forever. Best practice: pin SHA + comment tag tham khảo. Tools như dependabot có thể auto bump SHA khi có version mới.

Anti-pattern "Ice Cream Cone" trong testing là:

  • Quá nhiều integration test
  • Pyramid ngược: nhiều E2E, ít unit → CI chậm, flaky
  • Test code trong production
  • Không có test
Ice Cream Cone (ngược pyramid): nhiều E2E (cone đỉnh phía trên), ít unit. Hậu quả: CI 30+ phút, flaky (browser test không deterministic), khó debug khi fail (lỗi ở đâu trong stack?). Sửa: viết test ở level thấp nhất có thể (unit > integration > E2E).

Mục tiêu thời gian pipeline CI/CD nên dưới:

  • 10 phút (Etsy, GitLab benchmark) — pipeline chậm khiến dev cuối ngày commit dồn, CI quá tải, vòng luẩn quẩn
  • 1 giờ
  • 30 phút
  • Càng dài càng tốt
Pipeline 10 phút: dev có thể chờ và iterate. Pipeline 1 giờ: dev push xong đi làm việc khác → khi pipeline fail, mất context → fix lâu. Cách rút ngắn: cache, parallel jobs, test sharding, fail fast (lint trước test), only run affected tests.

"Pipeline as Code" nghĩa là:

  • Pipeline được viết bằng Python
  • Có pipeline cho code
  • Pipeline definition (YAML/Groovy) lưu trong repo (versioned), thay vì click-config trên UI
  • Pipeline tự động viết code
Pipeline as Code: .github/workflows/*.yml, .gitlab-ci.yml, Jenkinsfile — file commit vào repo. Lợi ích: versioned, code review, branch lifecycle (test pipeline thay đổi trên feature branch), audit trail. Đối lập: Jenkins UI clicks → "snowflake" config, không reproducible.

Pipeline security KHÔNG bao gồm practice nào sau đây?

  • Pin action theo SHA
  • OIDC short-lived token thay long-lived secret
  • Branch protection require approval
  • Print secret vào log để debug
In secret vào log = xuất secret vào lịch sử (CI logs giữ lâu). GitHub Actions tự động mask secret nhưng base64-encode/JSON-encode có thể bypass. Best practice: không bao giờ print secret. Khi debug: print hash hoặc partial. Pipeline là attack surface lớn — production deploy key thường ở đó.

Hoàn thành Chương 4. Tiếp theo: Chương 5 — Containers & Docker →