CI/CD overview - Phần 1/2 - Vấn đề, khái niệm và các khối tạo nên pipeline
Bài 1/6 trong series CI/CD và Kubernetes. Bài viết dành cho người đã biết Docker cơ bản và muốn hiểu cách đưa một thay đổi từ source code đến môi trường chạy một cách có kiểm soát.
Mục tiêu
Phần này tập trung tìm hiểu các nội dung sau:
- phân biệt Continuous Integration, Continuous Delivery và Continuous Deployment;
- hiểu CI/CD như một hệ thống phản hồi gồm quality gate, artifact promotion và telemetry;
- giải thích vai trò của pipeline, stage, job, runner, artifact, container registry và environment — các khối tạo nên một pipeline.
Vấn đề CI/CD giải quyết
Một Docker image giúp đóng gói ứng dụng và dependency thành cùng một đơn vị có thể chạy ở nhiều môi trường. Tuy nhiên, image không tự trả lời các câu hỏi vận hành:
- Ai chạy test trước một release?
- Image nào tương ứng với commit nào?
- Ai được phép đẩy image lên registry?
- Khi nào phiên bản mới được deploy?
- Nếu deploy lỗi, làm sao biết lỗi ở bước nào và quay lại phiên bản ổn định?
Nếu mỗi lần release đều dựa vào một chuỗi lệnh ghi trong ghi chú cá nhân, kết quả phụ thuộc vào người thực hiện và trạng thái máy của họ. CI/CD chuyển chuỗi thao tác này thành workflow có phiên bản, lặp lại được và có log.
Trong hình thức đơn giản nhất, thay đổi đi qua một chuỗi quality gate và release gate để tạo thành feedback loop:

Mỗi điểm quyết định là một gate. Nếu test thất bại, image không nên được publish. Nếu build thất bại, không có gì để deploy. Nếu rollout không hoàn tất, pipeline phải báo lỗi thay vì tạo cảm giác release đã thành công.
CI, Continuous Delivery và Continuous Deployment
Ba khái niệm thường được gọi chung là CI/CD nhưng không hoàn toàn giống nhau.
Continuous Integration — tích hợp liên tục
Continuous Integration (CI) là việc thường xuyên hợp nhất các thay đổi nhỏ vào nhánh chung và tự động kiểm tra chúng. Một pipeline CI thường thực hiện lint, unit test, integration test và build. Mục tiêu của CI không chỉ là “có server chạy test”. Điều quan trọng hơn là rút ngắn thời gian từ lúc tạo lỗi đến lúc phát hiện lỗi. Một commit nhỏ bị từ chối sau vài phút dễ sửa hơn một tập hợp thay đổi lớn chỉ được kiểm tra vào cuối tuần.
Continuous Delivery — luôn sẵn sàng cho release
Continuous Delivery mở rộng CI để phần mềm luôn ở trạng thái có thể release. Pipeline tạo artifact đã kiểm tra, lưu nó ở nơi đáng tin cậy và chuẩn bị các bước deploy. Quyết định đưa phiên bản đó lên production vẫn có thể cần phê duyệt thủ công. Ví dụ: tag v1.1.0 tạo image đã test trong registry. Một người phụ trách kiểm tra release notes rồi nhấn nút deploy. Quy trình đã tự động hóa, nhưng thời điểm release vẫn là quyết định của con người.
Continuous Deployment — tự động deploy
Continuous Deployment đi thêm một bước: mọi thay đổi vượt qua đầy đủ quality gate sẽ tự động được đưa đến environment đích, không cần bước phê duyệt thủ công. Continuous Deployment không phải lúc nào cũng tốt hơn Continuous Delivery. Chọn mô hình nào phụ thuộc vào rủi ro sản phẩm, quy định, khả năng test và khả năng quan sát hệ thống. Điểm chung là cùng một artifact đã được kiểm tra phải được đưa qua các môi trường; không build lại một phiên bản khác ngay trước production.
Có thể hình dung ba mức độ tự động hóa như các lớp mở rộng dần:

CI trả lời “thay đổi này có tích hợp an toàn không?”. Continuous Delivery trả lời “revision này đã sẵn sàng để release chưa?”. Continuous Deployment thêm quyết định “nếu mọi điều kiện đều đạt, hệ thống tự deploy”.
CI/CD là một hệ thống phản hồi
CI/CD thường được mô tả như dây chuyền tự động hóa, nhưng bản chất sâu hơn là một hệ thống phản hồi. Một thay đổi được thực hiện, hệ thống đo kết quả rồi đưa tín hiệu trở lại cho đội ngũ. Vòng phản hồi càng ngắn và rõ, chi phí sửa sai càng thấp.

Ba thuộc tính quan trọng
- Repeatability — khả năng lặp lại: cùng source, dependency và cấu hình phải tạo cùng kết quả. Pipeline-as-code và dependency lock file giảm khác biệt giữa các lần chạy.
- Traceability — khả năng truy vết: từ revision đang chạy phải tìm được commit, pipeline và artifact; từ commit phải biết đã đi qua những môi trường nào.
- Recoverability — khả năng phục hồi: quy trình phải có cách dừng rollout, rollback hoặc release bản sửa lỗi. Tốc độ deploy chỉ có ý nghĩa khi sự cố cũng được phục hồi nhanh.
Quality gate không chỉ là test pass/fail
Quality gate là điều kiện một revision phải đạt trước khi đi tiếp. Nó có thể gồm test, lint, security scan, review, policy hoặc tín hiệu sức khỏe sau deploy. Gate nên tự động khi tiêu chí có thể diễn đạt bằng máy; phê duyệt thủ công chỉ nên dùng cho quyết định cần trách nhiệm nghiệp vụ hoặc kiểm soát rủi ro.
Các lớp test có chi phí và phạm vi khác nhau:

Không nên đẩy toàn bộ niềm tin vào end-to-end test. Test chậm và dễ flaky làm vòng phản hồi dài; unit test nhanh nhưng không bắt được lỗi tích hợp. Một pipeline tốt phối hợp nhiều lớp và đặt kiểm tra rẻ, nhanh ở phía trước.
Các khối tạo nên một pipeline
Một pipeline nối sự kiện trong source control với môi trường thực thi và đầu ra có thể lưu trữ:

Pipeline
Pipeline là toàn bộ workflow được kích hoạt bởi một sự kiện như push commit, mở merge request, tạo tag hoặc bấm chạy thủ công. Trạng thái pipeline cho biết workflow hoàn tất hay dừng ở đâu. Pipeline nên được lưu cùng source code để thay đổi workflow cũng đi qua review và lịch sử Git. Đây thường được gọi là pipeline as code. Nó không bảo đảm pipeline đúng, nhưng biến release process từ kiến thức truyền miệng thành cấu hình có thể kiểm tra và truy vết.
Stage và job
Stage là một pha logic, ví dụ test, package và deploy. Job là đơn vị công việc cụ thể trong một stage. Nhiều job độc lập trong cùng stage có thể chạy song song; stage sau thường chỉ bắt đầu khi stage trước thành công.
Một thiết kế dễ đọc có thể là:
yaml
stages: [test, package, deploy]
unit_test:
stage: test
script:
- npm test
package_image:
stage: package
script:
- docker build ...
deploy_application:
stage: deploy
script:
- kubectl set image ...
Đây là mô hình minh họa, không phải toàn bộ pipeline của lab. Ý nghĩa chính là test, đóng gói và deploy là ba trách nhiệm khác nhau. Stage tạo thứ tự dễ hiểu, còn quan hệ needs tạo một directed acyclic graph (DAG) giữa các job. Với DAG, job chỉ chờ đúng dependency của nó thay vì chờ mọi job trong stage trước. Điều này rút ngắn pipeline nhưng đòi hỏi dependency phải được khai báo rõ; chạy song song hai job cùng sửa một môi trường có thể gây race condition.
Runner
Runner là agent nhận job từ GitLab và thực thi script. Job có thể yêu cầu môi trường Node.js để test, Docker CLI để build image hoặc kubectl để deploy. Runner cần đủ công cụ và kết nối mạng cho nhiệm vụ, nhưng không nên mặc nhiên có quyền quản trị toàn bộ hạ tầng. Runner có thể dùng chung hoặc dành riêng cho một project. Runner dùng chung tăng hiệu quả tài nguyên; runner riêng giúp cô lập mạng và credential. Dù theo mô hình nào, job nên chạy trong môi trường tạm thời và không phụ thuộc vào file còn sót từ pipeline trước.
Artifact
Artifact là đầu ra được pipeline lưu lại để job khác hoặc người dùng tải xuống: binary, báo cáo test, checksum hay metadata release. Artifact thường có thời hạn lưu trữ và gắn với một pipeline cụ thể. Container image cũng là một đầu ra của build, nhưng thường được lưu trong container registry thay vì cơ chế artifact thông thường. Cần phân biệt artifact và cache. Artifact là đầu ra cần truyền hoặc lưu để truy vết; cache là tối ưu hiệu năng, chẳng hạn thư mục package đã tải. Pipeline vẫn phải đúng khi cache bị xóa. Nếu thiếu cache làm build sai, cache đang bị dùng như một dependency ẩn.
Container registry
Registry là kho lưu image theo repository và tag. GitLab Container Registry trong lab giữ image MQTT broker. Kubernetes tải image từ registry khi tạo Pod mới. Tag dễ đọc như v1.1.0 biểu diễn phiên bản release; tag theo commit SHA giúp truy vết chính xác source. Image ID hoặc digest mới là định danh nội dung bất biến. Vì vậy pipeline không được ghi đè một release tag đã tồn tại.
Environment và deployment
Environment là đích logic như development, staging hoặc production. Deployment là một lần đưa một artifact cụ thể vào environment. Tách hai khái niệm này giúp trả lời chính xác “production đang chạy artifact nào?” và “artifact này đã từng đi qua staging chưa?”. Biến cấu hình theo môi trường nên được cấp tại thời điểm deploy, còn nội dung ứng dụng phải giữ nguyên. Nếu source hoặc image bị build lại cho từng môi trường, ta mất bảo đảm rằng production nhận đúng artifact đã được test.
Đây là các khối nền tảng của một pipeline. Phần tiếp theo sẽ áp dụng chúng vào pipeline MQTT broker thật trong lab.
All rights reserved