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
| Mô hình | Đặc trưng | Ai 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
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
| Tool | Type | Pros | Cons |
|---|---|---|---|
| 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
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":
9.1. Mỗi level
| Level | Đo gì | Speed | Stability | Cost |
|---|---|---|---|---|
| Unit | 1 function/class isolated | ms | High | Low |
| Integration | Module tương tác (DB, API) | seconds | Medium | Medium |
| E2E | User journey full | minutes | Low (flaky) | High |
| Manual | UX, exploratory | hours | — | Highest |
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, Playwrightretries: 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.
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.
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.
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%).
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
| Strategy | Downtime | Resource cost | Risk | Rollback |
|---|---|---|---|---|
| Recreate | Yes | 1× | Med | Slow (re-deploy) |
| Rolling | No | ~1× (1 instance extra) | Med | Roll back rolling |
| Blue-Green | No | 2× | Low | Instant (switch back) |
| Canary | No | 1.05× | Lowest | Quick (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_targetkhô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
- 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.
- Matrix testing: extend pipeline để test trên Node 18/20/22 và Ubuntu/macOS/Windows.
- Cache: thêm npm cache. Đo thời gian: lần 1 (no cache) vs lần 2+ (with cache).
- Service container: thêm integration test với Postgres service. Test query insert/select.
- Secret management: setup GitHub Secrets. Pipeline deploy lên S3 dùng AWS credential. Sau đó migrate sang OIDC.
- Artifact: build job tạo dist/, deploy job download dist/ và push lên hosting.
- Branch protection: setup main branch protection: require CI pass, ≥ 1 approver, no force push. Test thử push thẳng.
- Reusable workflow: extract test job thành reusable workflow. Dùng từ 2 repo khác nhau.
- Canary deploy simulation: dùng Argo Rollouts / Flagger trên minikube. Deploy v2 với canary 20%, monitor, mở rộng dần.
- 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.
- 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.
- 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 ở:
DORA report 2024 chỉ ra rằng deploy frequency và stability:
Test Pyramid khuyến nghị tỷ lệ test:
OIDC trong GitHub Actions deploy AWS tốt hơn AWS_ACCESS_KEY long-lived ở điểm nào?
Blue-Green deploy có ưu điểm gì so với Rolling Update?
Pin GitHub Action theo SHA thay vì tag (vd v4) là vì:
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à:
Mục tiêu thời gian pipeline CI/CD nên dưới:
"Pipeline as Code" nghĩa là:
.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?
Hoàn thành Chương 4. Tiếp theo: Chương 5 — Containers & Docker →