Mở đầu — vì sao bài này quan trọng
Nếu bạn từng ngồi trong một cuộc họp kỹ thuật và nghe ai đó nói "team mình đã làm CI/CD rồi", rất có thể mỗi người trong phòng lại hiểu câu đó theo một nghĩa khác nhau. Có người nghĩ nó có nghĩa là "code tự động chạy test khi push". Có người tưởng nó là "cứ merge vào main là tự động lên production". Có người lại nghĩ nó chỉ đơn giản là "team có dùng Jenkins/GitHub Actions". Cả ba cách hiểu này đều đúng một phần, và cũng đều sai một phần.
Vấn đề nằm ở chỗ cụm từ "CI/CD" thực ra gộp chung ba khái niệm hoàn toàn khác nhau về mặt kỹ thuật lẫn tổ chức: Continuous Integration (CI), Continuous Delivery (CD) và Continuous Deployment (CD). Rắc rối lớn nhất là hai chữ "CD" cuối cùng viết tắt giống hệt nhau nhưng lại mang hai ý nghĩa rất khác biệt — một cái nói về khả năng triển khai, một cái nói về việc tự động triển khai. Nhầm lẫn giữa chúng dẫn đến những hậu quả rất thực tế: bạn hứa với sếp một mức độ tự động hóa mà team chưa đạt tới, bạn thiết kế pipeline thiếu bước phê duyệt cần thiết, hoặc bạn đánh giá sai độ trưởng thành (maturity) của quy trình phát hành.
Bài này có một nhiệm vụ duy nhất và rất tập trung: giúp bạn phân biệt rạch ròi ba khái niệm CI, Continuous Delivery và Continuous Deployment, hiểu ranh giới chính xác giữa chúng, và biết mình đang đứng ở đâu trên hành trình đó. Chúng ta sẽ không đi sâu vào cách viết workflow YAML hay cấu hình runner (những phần đó dành cho các bài sau). Ở đây, mục tiêu là làm sạch tư duy khái niệm — vì một khi bạn hiểu đúng ranh giới, mọi bài học kỹ thuật phía sau sẽ trở nên dễ nắm bắt hơn rất nhiều.
Khái niệm cốt lõi
Cách dễ nhất để hình dung là xem cả ba như một chuỗi liên tiếp, mỗi bước xây trên nền bước trước. Bạn không thể có Continuous Delivery nếu chưa có CI vững chắc, và không thể có Continuous Deployment nếu chưa có Continuous Delivery. Đây là ba nấc thang, không phải ba lựa chọn song song.
CI — Continuous Integration (Tích hợp liên tục)
CI trả lời câu hỏi: "Code của nhiều người có ghép lại được với nhau và còn hoạt động không?"
Ý tưởng cốt lõi của CI là mỗi lập trình viên merge code của mình vào nhánh chung thường xuyên — lý tưởng là ít nhất một lần mỗi ngày — và mỗi lần merge đó tự động kích hoạt build và test. Từ khóa quan trọng là "integration" (tích hợp). Trước thời CI, các team thường làm việc riêng lẻ hàng tuần, thậm chí hàng tháng, rồi đến cuối cùng mới ghép code lại với nhau. Giai đoạn ghép đó thường là một cơn ác mộng — gọi là "integration hell" (địa ngục tích hợp) — vì hàng loạt xung đột và lỗi tương thích dồn lại một lúc.
CI giải quyết bằng cách chia nhỏ nỗi đau: thay vì ghép một lần lớn đầy rủi ro, bạn ghép liên tục từng chút một. Mỗi lần push code, một pipeline tự động sẽ:
- Lấy code mới nhất và biên dịch (build).
- Chạy bộ kiểm thử tự động (unit test, integration test).
- Báo cáo ngay lập tức nếu có gì đó hỏng.
Continuous Delivery — Giao hàng liên tục
Continuous Delivery mở rộng CI thêm một bước: sau khi code đã build và test xong, nó tự động đóng gói và đưa lên các môi trường trung gian (như staging, pre-production), và giữ artifact luôn ở trạng thái sẵn sàng để phát hành lên production bất cứ lúc nào.
Từ khóa quan trọng ở đây là chữ "khả năng" (ability). Continuous Delivery nghĩa là bạn có thể bấm nút phát hành lên production bất kỳ lúc nào và mọi thứ đã sẵn sàng. Nhưng bước cuối cùng — nhấn nút để đưa lên production — vẫn là một quyết định của con người. Có một cổng phê duyệt thủ công (manual approval gate) ở đó.
Hãy hình dung như một chiếc xe đã được đổ đầy xăng, nổ máy sẵn, đứng ở vạch xuất phát. Nó có thể lăn bánh bất cứ lúc nào — nhưng vẫn cần một người đạp ga. Continuous Delivery giữ chiếc xe luôn ở trạng thái đó: mọi phiên bản code merge vào main đều được tự động đưa qua toàn bộ quy trình cho tới ngay trước cửa production, và chỉ chờ một cú click.
Vì sao người ta lại muốn giữ bước thủ công này? Vì nhiều lý do rất chính đáng: cần chọn thời điểm phát hành (không ai muốn deploy lúc 5 giờ chiều thứ Sáu), cần phối hợp với marketing, cần tuân thủ quy định pháp lý, hoặc đơn giản là muốn có một con người ký duyệt trước khi ảnh hưởng đến khách hàng thật.
Continuous Deployment — Triển khai liên tục
Continuous Deployment đi thêm một bước cuối cùng và cũng là bước táo bạo nhất: bỏ luôn cổng phê duyệt thủ công. Mỗi thay đổi vượt qua toàn bộ pipeline test tự động sẽ được tự động đưa thẳng lên production, không cần con người bấm nút.
Từ khóa ở đây là "tự động hoàn toàn" (automatic). Với Continuous Deployment, khi một developer merge code vào main và tất cả các bước kiểm thử pass, code đó sẽ có mặt trên production trong vòng vài phút mà không ai phải làm gì thêm. Nếu test fail, pipeline dừng và code không lên. Không có con người nào ngồi giữa merge và production.
Đây chính là điểm phân biệt duy nhất giữa Continuous Delivery và Continuous Deployment, và nó cũng là chỗ hầu hết mọi người nhầm lẫn:
- Continuous Delivery: tự động tới ngay trước production, con người bấm nút cuối.
- Continuous Deployment: tự động luôn cả bước cuối, không có con người.
Một cách ghi nhớ rất dễ: Continuous Deployment = Continuous Delivery + tự động hóa bước phê duyệt cuối cùng. Nếu team bạn có một bước "manual approval" trước production, bạn đang làm Delivery chứ không phải Deployment. Đơn giản vậy thôi.
Bảng so sánh nhanh ba khái niệm
| Bước trong quy trình | CI | Continuous Delivery | Continuous Deployment |
|---|---|---|---|
| Merge code thường xuyên | ✅ | ✅ | ✅ |
| Auto build | ✅ | ✅ | ✅ |
| Auto test | ✅ | ✅ | ✅ |
| Auto đưa lên staging | ❌ | ✅ | ✅ |
| Sẵn sàng deploy production mọi lúc | ❌ | ✅ | ✅ |
| Deploy production tự động | ❌ | ❌ (cần người duyệt) | ✅ |
Tình huống thực tế
Ví dụ 1 — Tiki: chọn Continuous Delivery vì cần kiểm soát thời điểm
Hãy tưởng tượng đội kỹ thuật của một sàn thương mại điện tử lớn tại Việt Nam như Tiki. Họ có hàng trăm developer, mỗi ngày có thể có 200–300 lần merge code vào các dịch vụ khác nhau. Họ đã làm CI rất tốt: mỗi commit đều tự động build và chạy khoảng 15 phút test.
Câu hỏi đặt ra: có nên để mọi merge tự động lên thẳng production không? Đội ngũ quyết định không — họ chọn Continuous Delivery. Lý do rất thực tế: vào những đợt sale lớn như 11/11 hay 12/12, hệ thống chịu tải khủng khiếp, và một thay đổi tưởng chừng vô hại ở tầng thanh toán cũng có thể gây thiệt hại hàng tỷ đồng nếu deploy sai thời điểm. Vì vậy code luôn được đưa tự động lên staging, đội QA và trưởng nhóm xem xét, rồi mới bấm nút release theo lịch đã định — thường tránh giờ cao điểm và tránh các đợt khuyến mãi.
Bài học: Continuous Delivery là lựa chọn hợp lý khi thời điểm phát hành quan trọng với business. Không phải cứ tự động hóa tối đa là tốt nhất. Có cổng phê duyệt không có nghĩa là team "kém trưởng thành" — đôi khi đó là một quyết định kinh doanh có chủ đích.
Ví dụ 2 — Một startup fintech Singapore: leo từng nấc thang
Một startup fintech nhỏ ở Singapore, khoảng 12 kỹ sư, khi mới thành lập chỉ deploy bằng tay: SSH vào server, git pull, restart service. Mỗi lần deploy mất 40 phút và thỉnh thoảng quên chạy migration database, gây lỗi.
Họ bắt đầu hành trình cải thiện theo đúng ba nấc thang:
- Tháng 1–2 (làm CI): Thiết lập pipeline tự động build và test trên mỗi pull request. Số bug lọt ra staging giảm rõ rệt vì lỗi được bắt ngay khi merge.
- Tháng 3–5 (lên Continuous Delivery): Tự động đóng gói Docker image và đẩy lên môi trường staging sau mỗi merge. Việc lên production vẫn do CTO bấm nút mỗi tối. Thời gian deploy giảm từ 40 phút xuống còn 4 phút.
- Tháng 8 trở đi (lên Continuous Deployment): Sau khi đã tích lũy đủ độ tin cậy vào bộ test và có sẵn cơ chế giám sát cùng khả năng rollback, họ bỏ bước bấm nút thủ công. Giờ mỗi merge pass test là tự lên production, trung bình 15 lần deploy mỗi ngày.
Ví dụ 3 — Ngân hàng: vì sao Continuous Deployment không phải lúc nào cũng phù hợp
Một ngân hàng thương mại tại Việt Nam có đội phát triển core banking. Về mặt kỹ thuật, họ hoàn toàn đủ năng lực làm Continuous Deployment. Nhưng họ cố tình dừng ở Continuous Delivery, thậm chí với nhiều lớp phê duyệt.
Lý do là quy định (compliance). Trong ngành ngân hàng, mọi thay đổi lên hệ thống production phải có "vết" phê duyệt của người có thẩm quyền, phải qua change management, và phải có khả năng chứng minh với thanh tra rằng "thay đổi X được người Y duyệt vào lúc Z". Continuous Deployment — deploy tự động không có con người — về mặt kỹ thuật là mâu thuẫn với yêu cầu này.
Bài học: Continuous Deployment không phải là "đích đến cao nhất mà mọi team phải hướng tới". Nó là một lựa chọn phù hợp với một số bối cảnh (sản phẩm web tốc độ cao, rủi ro thấp) và không phù hợp với bối cảnh khác (tài chính, y tế, hàng không). Phân biệt được hai chữ CD giúp bạn nói chuyện chính xác với bộ phận compliance: "Chúng ta làm Continuous Delivery — luôn có người duyệt" nghe rất khác với "Chúng ta deploy tự động".
Hướng dẫn từng bước
Đây là cách bạn tự xác định team mình đang đứng ở đâu và cần gì để lên nấc tiếp theo.
- Xác định điểm dừng hiện tại của pipeline. Hãy vẽ ra hành trình một dòng code từ lúc developer commit đến lúc nó chạy trên production. Đánh dấu bước cuối cùng được tự động hóa. Nếu tự động dừng ở "test pass" → bạn đang ở CI. Nếu tự động tới staging và chờ người duyệt → Continuous Delivery. Nếu tự động luôn cả production → Continuous Deployment.
- Kiểm tra xem có "cổng thủ công" nào không. Tìm chính xác chỗ nào trong quy trình cần một con người bấm nút, gõ lệnh, hay phê duyệt. Số lượng và vị trí các cổng này quyết định bạn thuộc nhóm nào. Một cổng ngay trước production là dấu hiệu kinh điển của Continuous Delivery.
- Đánh giá độ tin cậy của bộ test. Đây là điều kiện tiên quyết để leo nấc thang. Tự hỏi: "Nếu bỏ hết bước duyệt thủ công, mình có dám để code tự lên production không?" Nếu câu trả lời là "không, vì test chưa bắt hết lỗi" — thì bạn chưa sẵn sàng cho Continuous Deployment, dù công cụ đã đủ.
- Kiểm tra khả năng phục hồi. Continuous Deployment chỉ an toàn khi bạn có giám sát tốt và có thể rollback nhanh. Hãy chắc chắn team trả lời được: "Nếu code lỗi lọt lên production lúc 3 giờ sáng, bao lâu chúng ta phát hiện và quay lui được?"
- Chọn nấc thang phù hợp với business, không phải theo phong trào. Sau khi biết mình đang ở đâu và có thể lên đâu, hãy hỏi: nấc tiếp theo có thực sự mang lại giá trị cho sản phẩm này không? Với sản phẩm nội bộ ít rủi ro, Continuous Deployment rất đáng. Với hệ thống chịu quy định ngặt nghèo, dừng ở Continuous Delivery mới là đúng.
Lỗi thường gặp & mẹo
Lỗi 1 — Dùng "CI/CD" như một khối duy nhất mà không biết mình đang nói CD nào. Khi ai đó nói "chúng ta có CI/CD", hãy tập thói quen hỏi lại: "CD là Delivery hay Deployment? Có bước duyệt thủ công trước production không?" Câu hỏi này lập tức làm rõ mọi hiểu lầm.
Lỗi 2 — Nghĩ Continuous Deployment luôn "xịn hơn" Continuous Delivery. Chúng khác nhau về mức độ tự động, không phải về chất lượng. Một team làm Continuous Delivery kỷ luật hoàn toàn có thể "trưởng thành" hơn một team làm Continuous Deployment ẩu.
Lỗi 3 — Nhầm giữa "deploy" và "release". Với Continuous Deployment, code được deploy tự động lên production, nhưng tính năng có thể vẫn ẩn với người dùng (thông qua feature flag). Deploy là đưa code lên máy chủ; release là bật tính năng cho người dùng thấy. Đây là hai việc khác nhau và không nằm trong phạm vi bài này, nhưng cần phân biệt để không nhầm "deploy tự động" với "đẩy tính năng chưa hoàn thiện cho khách hàng".
Lỗi 4 — Cố nhảy cóc lên Continuous Deployment khi CI còn yếu. Nếu bộ test của bạn hay báo lỗi giả (flaky) hoặc bỏ sót lỗi thật, việc bỏ cổng thủ công sẽ biến pipeline thành một cỗ máy đẩy bug lên production tự động. Củng cố CI trước đã.
Mẹo ghi nhớ nhanh: CI = code ghép được và test pass. Delivery = luôn sẵn sàng release, người bấm nút. Deployment = tự bấm nút luôn. Ba câu này gói gọn toàn bộ bài học.
Bài tập thực hành
- Tự chẩn đoán pipeline. Chọn một dự án bạn đang tham gia (hoặc một dự án mã nguồn mở bạn biết). Vẽ hành trình của code từ commit đến production và xác định chính xác dự án đó đang ở nấc nào: CI, Continuous Delivery, hay Continuous Deployment. Ghi rõ cổng thủ công nằm ở đâu (nếu có).
- Phân loại tình huống. Với mỗi mô tả dưới đây, hãy xác định đó là khái niệm nào:
- Viết một đoạn thuyết phục. Giả sử bạn là tech lead của một startup giao đồ ăn. Viết 3–4 câu giải thích cho CEO (người không rành kỹ thuật) rằng team nên dừng ở Continuous Delivery thay vì Continuous Deployment trong 6 tháng đầu, và lý do vì sao.
- Lập lộ trình. Cho một team đang deploy hoàn toàn thủ công, hãy liệt kê thứ tự các bước họ cần làm để leo dần lên Continuous Deployment. Chú ý điều kiện tiên quyết của mỗi nấc.
Tóm tắt
Ba khái niệm bị gộp chung trong cụm "CI/CD" thực chất là ba nấc thang liên tiếp, mỗi nấc xây trên nấc trước:
- CI (Continuous Integration): merge code thường xuyên, tự động build và test. Kết thúc ở một artifact đã kiểm chứng. Không nói gì về triển khai.
- Continuous Delivery: tự động đưa code tới ngay trước production và giữ nó luôn sẵn sàng để release, nhưng bước cuối cùng do con người bấm nút. Từ khóa: khả năng triển khai bất cứ lúc nào.
- Continuous Deployment: bỏ luôn cổng thủ công, mỗi thay đổi pass test được tự động đẩy thẳng lên production. Từ khóa: tự động hoàn toàn.