Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là kỹ sư vận hành tại một startup fintech ở TP.HCM. Mỗi lần deploy phiên bản mới, cả team phải thức đến 2 giờ sáng: một người copy file lên server qua FTP, một người chạy tay các lệnh migrate database, một người ngồi bấm F5 kiểm tra xem trang có "trắng" không. Nếu hỏng, cả team hoảng loạn rollback bằng cách... copy đè lại bản cũ. Nghe quen không? Đó chính xác là cuộc sống trước khi có CI/CD.
CI/CD Pipeline — Continuous Integration (tích hợp liên tục) và Continuous Delivery/Deployment (chuyển giao/triển khai liên tục) — là "dây chuyền sản xuất tự động" biến một dòng lệnh git push của lập trình viên thành một phiên bản chạy trên production, mà không cần ai phải thao tác tay và không cần thức đêm. Nó là xương sống của mọi tổ chức tech hiện đại, và với dân Operations, đây là nơi bạn kiểm soát chất lượng, tốc độ và độ an toàn của mọi thay đổi đi vào hệ thống.
Bài này tập trung riêng vào cấu trúc của pipeline — ba nhóm giai đoạn cốt lõi Build, Test, Deploy — cách chúng nối tiếp nhau, và cách một kỹ sư Operations thiết kế, vận hành, tối ưu chúng. Chúng ta sẽ không đi sâu vào từng chiến lược triển khai như Blue-Green hay Canary (đó là Bài 16 và Bài 40 GitOps), mà tập trung vào bộ khung chung mà bạn phải làm chủ trước.
Khái niệm cốt lõi
CI/CD là gì và khác nhau ở đâu
Continuous Integration (CI) là thực hành mỗi khi lập trình viên đẩy code lên, hệ thống tự động build và chạy test để phát hiện lỗi tích hợp ngay lập tức, thay vì để dồn đến cuối sprint mới phát hiện "code của A và B không chạy chung được". Mục tiêu của CI: giữ nhánh chính (main/master) luôn ở trạng thái build được và test pass.
Continuous Delivery là bước tiếp theo: sau khi CI xanh, hệ thống tự động đóng gói một artifact (image, package) sẵn sàng để deploy bất cứ lúc nào, nhưng việc bấm nút deploy lên production vẫn do con người quyết định.
Continuous Deployment đi xa hơn một bậc: nếu mọi test pass, artifact được deploy thẳng lên production không cần người bấm nút. Nhiều công ty lớn như Amazon deploy hàng nghìn lần mỗi ngày theo cách này.
Điểm mấu chốt cần nhớ: CI là về chất lượng code, CD là về tốc độ đưa code ra ngoài. Một pipeline hoàn chỉnh nối cả hai thành dòng chảy liền mạch.
Các giai đoạn (stages) chuẩn của một pipeline
Một pipeline điển hình chảy qua các stage tuần tự, mỗi stage phải "xanh" thì mới sang stage tiếp theo:
1. Source (Nguồn) — kích hoạt bằng git push. Đây là điểm khởi đầu. Lập trình viên git push hoặc mở một pull request, một webhook từ GitHub/GitLab bắn tín hiệu tới hệ thống CI (Jenkins, GitHub Actions, GitLab CI...). Pipeline kéo (checkout) đúng commit đó về. Một nguyên tắc vàng: pipeline luôn build từ code trong git, không bao giờ từ máy cá nhân của ai — đây là nền tảng của tính reproducible (tái lập được).
2. Build (Biên dịch & đóng gói). Ở giai đoạn này, code nguồn được biến thành một sản phẩm chạy được: compile mã (với Java, Go, C#...), cài dependencies (npm install, composer install), và quan trọng nhất với hệ thống hiện đại — build một container image (thường là Docker image) rồi gắn tag theo commit. Nguyên tắc cốt lõi: build một lần, dùng ở mọi môi trường (build once, deploy everywhere). Nghĩa là artifact build ra ở đây sẽ được dùng y hệt cho staging và production, không build lại. Nếu build lại ở mỗi môi trường, bạn có nguy cơ hai bản khác nhau về dependency hay biến môi trường.
3. Test (Kiểm thử). Đây là "cửa chất lượng". Test được chia thành nhiều lớp, chạy từ nhanh-rẻ đến chậm-đắt:
- Unit test: kiểm tra từng hàm/module riêng lẻ, chạy trong vài giây.
- Integration test: kiểm tra các thành phần ghép với nhau (ví dụ code gọi database thật hoặc mock).
- Security scan: quét lỗ hổng trong dependencies (SCA — như
npm audit, Trivy, Snyk) và quét code tĩnh (SAST). Với dân Ops, đây là chốt chặn để không đẩy thư viện dính CVE lên production. - Test coverage & linting: đảm bảo code đạt ngưỡng bao phủ và tuân thủ chuẩn.
4. Deploy (Triển khai). Artifact đã qua test được đưa lên môi trường: thường là staging trước, rồi production. Ở đây pipeline áp dụng các chiến lược như rolling update, canary, blue-green (chi tiết ở Bài 16). Với Ops, giai đoạn này còn bao gồm database migration, cập nhật config, và quan trọng nhất — cơ chế rollback tự động khi health check thất bại.
Artifact và Pipeline as Code
Hai khái niệm bạn phải nắm:
Artifact là sản phẩm đầu ra của stage Build — bất biến (immutable) và được đánh phiên bản. Nó nằm trong một artifact registry (Docker Registry, Nexus, Artifactory). Việc gắn tag theo commit SHA (ví dụ myapp:a3f8c1) cho phép bạn truy vết chính xác phiên bản nào đang chạy trên production và rollback về đúng bản trước đó.
Pipeline as Code: định nghĩa toàn bộ pipeline bằng file YAML nằm ngay trong repo (.github/workflows/, .gitlab-ci.yml, Jenkinsfile). Nhờ vậy pipeline được version control, review qua pull request, và tái lập được — thay vì cấu hình bằng tay trên giao diện web mà không ai biết ai đã đổi gì.
Tình huống thực tế
Ví dụ 1: Tiki chuyển từ deploy thủ công sang pipeline tự động
Một đội backend giả định tại một sàn thương mại điện tử lớn của Việt Nam (tương tự Tiki) từng deploy thủ công vào 23h mỗi tối thứ Ba. Quy trình: SSH vào 12 server, git pull, chạy composer install, restart PHP-FPM lần lượt. Trung bình mất 45 phút và cứ khoảng 1 trong 5 lần lại có server bị "lệch" — server này đã update, server kia chưa, gây lỗi 500 cho một phần người dùng.
Họ dựng pipeline trên GitLab CI: mỗi merge vào main sẽ build một Docker image gắn tag commit, chạy 1.200 unit test trong 4 phút, quét bảo mật bằng Trivy, rồi deploy rolling qua Kubernetes. Kết quả sau 3 tháng: thời gian deploy giảm từ 45 phút xuống 6 phút, tỷ lệ deploy lỗi giảm từ 20% xuống dưới 2%, và quan trọng nhất — họ deploy được vào giữa ban ngày vì rollback tự động chỉ mất 40 giây.
Bài học: giá trị lớn nhất của pipeline không phải là "nhanh hơn", mà là nhất quán và có thể rollback — điều khiến team dám deploy thường xuyên hơn thay vì gom một đống thay đổi vào một lần deploy đêm rủi ro cao.
Ví dụ 2: Sự cố "build khác nhau giữa các môi trường" tại một startup logistics
Một startup logistics ở Đông Nam Á gặp sự cố khó hiểu: code chạy hoàn hảo ở staging nhưng crash ở production. Điều tra ra nguyên nhân: pipeline của họ build lại image ở mỗi môi trường. Ở staging build lúc 10h sáng, npm install kéo về lodash@4.17.20; production build lúc 3h chiều thì thư viện đã ra bản 4.17.21 với một thay đổi hành vi nhỏ. Hai artifact khác nhau dù cùng một commit.
Họ sửa bằng cách áp dụng nguyên tắc build once, deploy everywhere: image được build đúng một lần ở stage Build, gắn tag commit-SHA, đẩy vào registry, và mọi môi trường đều pull chính image đó. Đồng thời họ khóa (lock) dependency bằng package-lock.json được commit vào repo.
Bài học: artifact phải bất biến. Nếu bạn không đảm bảo điều này, môi trường staging trở nên vô nghĩa vì nó không kiểm thử đúng thứ sẽ chạy trên production.
Ví dụ 3: Pipeline chậm giết chết năng suất tại một công ty SaaS
Một công ty SaaS 40 kỹ sư than phiền pipeline mất 38 phút cho mỗi lần chạy. Vì lâu, lập trình viên gom nhiều thay đổi vào một PR lớn để "đỡ tốn công chờ", khiến review khó và bug nhiều hơn — một vòng xoáy xấu.
Đội Platform phân tích và tối ưu: cache dependencies (không tải lại node_modules mỗi lần), chạy song song các nhóm test độc lập trên nhiều runner, và tách stage: unit test (nhanh) chặn merge, còn integration test nặng chạy song song không chặn. Thời gian giảm còn 9 phút. Số PR nhỏ tăng lên, tần suất deploy tăng gấp đôi.
Bài học: tốc độ pipeline không phải chuyện "nice to have" — nó định hình hành vi của cả đội. Pipeline chậm khuyến khích thói quen xấu; pipeline nhanh khuyến khích thay đổi nhỏ, an toàn, thường xuyên.
Hướng dẫn từng bước
Dưới đây là cách thiết kế một pipeline CI/CD cơ bản từ đầu, dạng Pipeline as Code với GitHub Actions (nguyên tắc áp dụng được cho mọi công cụ):
Bước 1 — Xác định trigger (Source). Quyết định pipeline chạy khi nào: khi push lên nhánh feature (chỉ chạy build + test), khi mở PR (chạy full CI làm cửa chất lượng), khi merge vào main (chạy full + deploy staging).
Bước 2 — Viết stage Build. Định nghĩa các bước: checkout code, setup runtime, cài dependency (có cache), build image và gắn tag theo commit SHA.
name: CI/CD
on:
pull_request:
push:
branches: [main]jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # cache dependency để chạy nhanh
- run: npm ci # cài từ lock file, tái lập được
- run: docker build -t myapp:${{ github.sha }} .
Bước 3 — Viết stage Test. Tách các loại test, cho unit test chạy trước để fail fast:
test:
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint # kiểm tra chuẩn code
- run: npm test # unit test
- run: npm audit --audit-level=high # quét bảo mật dependency
Bước 4 — Định nghĩa quality gate. Đặt điều kiện: pipeline chỉ được sang stage deploy nếu tất cả test pass và coverage đạt ngưỡng (ví dụ 70%). Cấu hình branch protection để không ai merge được khi CI đỏ.
Bước 5 — Viết stage Deploy. Chỉ chạy khi ở nhánh main, đẩy image lên registry rồi triển khai:
deploy:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- run: docker push registry.example.com/myapp:${{ github.sha }}
- run: kubectl set image deployment/myapp myapp=registry.example.com/myapp:${{ github.sha }}
Bước 6 — Thêm health check và rollback. Sau khi deploy, gọi endpoint /health; nếu không trả về 200 trong vòng vài phút, tự động rollback về image trước. Đây là điểm mà Ops phải chăm chút nhất.
Bước 7 — Thêm quản lý secret an toàn. Không bao giờ hardcode mật khẩu, API key trong YAML. Dùng secret store của nền tảng (GitHub Secrets, Vault — xem Bài 33).
Bước 8 — Đo lường. Theo dõi 4 chỉ số DORA: tần suất deploy, lead time (từ commit đến production), tỷ lệ thất bại thay đổi, và thời gian khôi phục. Đây là thước đo sức khỏe pipeline.
Lỗi thường gặp & mẹo
Lỗi 1 — Test flaky (chập chờn). Test lúc pass lúc fail không phải do code mà do timing, thứ tự chạy, hoặc phụ thuộc mạng. Team dần mất niềm tin và bắt đầu "chạy lại cho đến khi xanh" — vô hiệu hóa toàn bộ giá trị của CI. Mẹo: cô lập và sửa hoặc cách ly test flaky ngay, đừng để chúng làm ô nhiễm pipeline.
Lỗi 2 — Pipeline quá chậm. Như ví dụ 3, pipeline trên 10-15 phút bắt đầu bào mòn năng suất. Mẹo: cache dependency, chạy song song, chia stage nhanh/chậm, và cân nhắc chỉ chạy test liên quan đến phần code thay đổi.
Lỗi 3 — Build lại ở mỗi môi trường. Vi phạm nguyên tắc build once. Mẹo: build một artifact bất biến, promote (thăng cấp) nó qua các môi trường.
Lỗi 4 — Quality gate quá lỏng hoặc quá chặt. Quá lỏng thì bug lọt lên production; quá chặt (bắt coverage 100%) thì team viết test rác cho đủ số. Mẹo: chọn ngưỡng hợp lý và bổ sung security scan làm gate bắt buộc.
Lỗi 5 — Không có rollback tự động. Deploy nhanh mà rollback thủ công thì khi sự cố xảy ra bạn vẫn hoảng loạn như thời FTP. Mẹo: rollback phải là một bước tự động trong pipeline, kích hoạt bởi health check.
Lỗi 6 — Secret lộ trong log pipeline. In biến môi trường chứa mật khẩu ra log là lỗi kinh điển. Mẹo: dùng secret masking và không bao giờ echo biến nhạy cảm.
Mẹo vàng cho Ops: hãy coi pipeline như một sản phẩm production thực thụ — nó cần được monitor, có SLO riêng, và khi nó hỏng thì đó cũng là một incident. Một pipeline "chết" chặn cả team ra hàng.
Bài tập thực hành
Bài 1 — Vẽ pipeline. Chọn một dự án bạn quen thuộc. Vẽ sơ đồ pipeline lý tưởng của nó với 4 stage Source → Build → Test → Deploy. Với mỗi stage, ghi rõ: công cụ dùng, thời gian ước tính, và điều kiện để "xanh" chuyển sang stage sau.
Bài 2 — Thiết kế quality gate. Liệt kê 5 kiểm tra bạn muốn đặt làm cửa chất lượng bắt buộc trước khi cho phép deploy production. Với mỗi kiểm tra, giải thích hậu quả nếu bỏ nó đi.
Bài 3 — Viết pipeline thật. Tạo một repo mẫu (một app Node hoặc PHP đơn giản) và viết file .github/workflows/ci.yml gồm build + unit test + npm audit. Push lên GitHub và quan sát pipeline chạy. Cố tình đẩy một commit làm hỏng test và xác nhận pipeline chuyển đỏ.
Bài 4 — Tối ưu tốc độ. Giả sử pipeline của bạn mất 30 phút. Đề xuất 3 cải tiến cụ thể để đưa xuống dưới 10 phút, và ước lượng mỗi cải tiến tiết kiệm bao nhiêu.
Bài 5 — Phân tích tình huống. Một đồng nghiệp đề nghị "bỏ qua test cho gấp vì đang có sự cố cần fix ngay". Bạn sẽ phản biện hoặc xử lý thế nào để vừa nhanh vừa an toàn?
Tóm tắt
CI/CD Pipeline là dây chuyền tự động biến git push thành một phiên bản chạy trên production một cách nhất quán, nhanh và an toàn. Bốn stage cốt lõi là Source (git push kích hoạt qua webhook), Build (compile, đóng gói, build image — theo nguyên tắc build một lần dùng mọi nơi), Test (unit → integration → security scan, xếp theo fail fast), và Deploy (đưa artifact bất biến lên môi trường kèm health check và rollback tự động).
Với dân Operations, ba điều quan trọng nhất cần khắc cốt: (1) artifact phải bất biến và đánh phiên bản để truy vết và rollback; (2) pipeline phải nhanh vì tốc độ định hình hành vi cả đội; (3) pipeline chính là hạ tầng production cần được monitor và coi trọng như mọi hệ thống khác. Làm chủ được bộ khung này, bạn đã có nền tảng để tiến tới các chủ đề sâu hơn như GitOps, deployment strategies và feature flags ở các bài sau.