CI/CD – Continuous Integration và Continuous Delivery/Deployment
CI/CD là một trong những nền tảng quan trọng của DevOps, giúp tự động hóa quá trình kiểm tra, xây dựng, đóng gói và triển khai phần mềm. Thay vì phải thực hiện thủ công từng bước mỗi khi lập trình viên cập nhật mã nguồn, CI/CD cho phép hệ thống tự động chạy các quy trình đã được cấu hình, phát hiện lỗi sớm và đưa phiên bản phần mềm mới đến môi trường sử dụng một cách nhanh chóng, nhất quán.
Trong phát triển phần mềm hiện đại, CI/CD được sử dụng rộng rãi trong các dự án Website, Backend, Mobile App, hệ thống Cloud và nhiều ứng dụng doanh nghiệp. Các công cụ như GitHub Actions, GitLab CI/CD, Jenkins, CircleCI và Azure Pipelines hỗ trợ xây dựng những quy trình tự động hóa phù hợp với quy mô của từng dự án.
Đối với lập trình viên, hiểu về CI/CD không chỉ giúp giảm các công việc lặp đi lặp lại mà còn giúp nâng cao chất lượng mã nguồn, hạn chế lỗi khi phát hành và phối hợp hiệu quả hơn trong môi trường làm việc nhóm.
1. Tổng quan về CI/CD
CI/CD là viết tắt của ba khái niệm liên quan đến tự động hóa quy trình phát triển và phát hành phần mềm:
-
CI – Continuous Integration: Tích hợp liên tục.
-
CD – Continuous Delivery: Phân phối liên tục.
-
CD – Continuous Deployment: Triển khai liên tục.
Ba khái niệm này có mối liên hệ chặt chẽ với nhau nhưng không hoàn toàn giống nhau.
CI tập trung vào việc tích hợp những thay đổi mã nguồn từ nhiều lập trình viên và kiểm tra chúng thường xuyên. Continuous Delivery mở rộng quy trình đó bằng cách chuẩn bị phần mềm để có thể phát hành bất cứ lúc nào. Continuous Deployment tiến thêm một bước bằng cách tự động đưa những thay đổi đã vượt qua toàn bộ điều kiện kiểm tra lên môi trường production.
Trong một dự án truyền thống, lập trình viên có thể viết mã nguồn, chạy kiểm thử trên máy cá nhân, tạo bản build, sao chép tệp lên máy chủ và cấu hình ứng dụng theo cách thủ công. Quy trình này dễ xảy ra sai sót khi dự án có nhiều thành viên hoặc phải phát hành thường xuyên.
CI/CD thay thế nhiều bước thủ công bằng một pipeline được định nghĩa trước. Khi có sự kiện như đẩy mã nguồn lên Git hoặc tạo Pull Request, hệ thống sẽ tự động thực hiện những công việc cần thiết theo thứ tự đã cấu hình.
Ví dụ, khi lập trình viên cập nhật một chức năng đăng nhập cho Website, hệ thống CI/CD có thể tự động:
-
Nhận mã nguồn mới từ GitHub.
-
Cài đặt các dependency cần thiết.
-
Kiểm tra định dạng và chất lượng mã nguồn.
-
Chạy unit test và các bài kiểm thử liên quan.
-
Build ứng dụng.
-
Đóng gói ứng dụng thành artifact hoặc Docker image.
-
Triển khai lên môi trường staging để kiểm tra.
-
Đưa ứng dụng lên production nếu đáp ứng đầy đủ điều kiện phát hành.
Nhờ đó, quá trình phát triển phần mềm trở nên có thể lặp lại, dễ kiểm soát và ít phụ thuộc vào thao tác cá nhân của từng lập trình viên.
2. Continuous Integration (CI)
Continuous Integration, hay tích hợp liên tục, là phương pháp yêu cầu các lập trình viên thường xuyên tích hợp những thay đổi mã nguồn của mình vào một nhánh chung trong hệ thống quản lý phiên bản.
Thay vì phát triển riêng biệt trong thời gian dài rồi mới hợp nhất mã nguồn, mỗi thành viên sẽ tích hợp thay đổi thường xuyên và để hệ thống tự động kiểm tra tính hợp lệ của những thay đổi đó.
2.1. Cách CI hoạt động
Một quy trình CI cơ bản thường bắt đầu khi lập trình viên thực hiện git push hoặc tạo Pull Request.
Ví dụ, một nhóm có ba lập trình viên cùng phát triển Website bán hàng:
-
Lập trình viên A xây dựng chức năng đăng nhập.
-
Lập trình viên B xây dựng chức năng quản lý sản phẩm.
-
Lập trình viên C xây dựng chức năng giỏ hàng.
Mỗi người làm việc trên một nhánh Git riêng. Khi một thành viên gửi thay đổi lên kho mã nguồn, hệ thống CI sẽ chạy các bước kiểm tra đã thiết lập.
Nếu mã nguồn không biên dịch được, có lỗi cú pháp hoặc unit test thất bại, pipeline sẽ đánh dấu lần kiểm tra đó là thất bại. Nhóm phát triển có thể xử lý lỗi ngay khi thay đổi còn nhỏ, thay vì đợi đến giai đoạn tích hợp cuối cùng.
Một pipeline CI thường bao gồm các bước:
-
Source checkout: Lấy mã nguồn từ repository.
-
Dependency installation: Cài đặt thư viện và công cụ cần thiết.
-
Static analysis: Phân tích mã nguồn mà không cần thực thi toàn bộ ứng dụng.
-
Linting: Kiểm tra quy tắc định dạng và phong cách lập trình.
-
Automated testing: Chạy các bài kiểm thử tự động.
-
Build verification: Xác nhận ứng dụng có thể được biên dịch hoặc đóng gói thành công.
-
Feedback: Trả về kết quả cho lập trình viên.
2.2. Lợi ích của CI
CI giúp phát hiện lỗi sớm trong quá trình phát triển. Khi một thay đổi làm hỏng chức năng đã có, hệ thống có thể phát hiện thông qua các bài kiểm thử hồi quy.
CI cũng giảm xung đột tích hợp do các thành viên thường xuyên đồng bộ mã nguồn với nhánh chung. Các lỗi phát sinh thường dễ truy tìm hơn vì mỗi lần kiểm tra gắn với một commit hoặc Pull Request cụ thể.
Ngoài ra, CI giúp nhóm duy trì một tiêu chuẩn chất lượng thống nhất. Tất cả thay đổi đều phải vượt qua cùng một tập hợp quy tắc trước khi được hợp nhất, thay vì phụ thuộc hoàn toàn vào việc mỗi lập trình viên có nhớ chạy kiểm tra hay không.
Tuy nhiên, CI không đảm bảo phần mềm hoàn toàn không có lỗi. Chất lượng của kết quả phụ thuộc vào độ bao phủ, tính chính xác và mức độ phù hợp của các bài kiểm thử cũng như các quy tắc kiểm tra được cấu hình.
3. Continuous Delivery và Continuous Deployment
Continuous Delivery và Continuous Deployment đều mở rộng quy trình CI bằng cách tự động hóa các bước chuẩn bị và phát hành phần mềm. Điểm khác biệt quan trọng nhất là cách phần mềm được đưa lên môi trường production.
3.1. Continuous Delivery
Continuous Delivery, hay phân phối liên tục, là phương pháp duy trì phần mềm ở trạng thái sẵn sàng phát hành sau khi vượt qua các bước build và kiểm thử cần thiết.
Khi pipeline chạy thành công, hệ thống có thể tạo ra một gói phần mềm hoàn chỉnh, lưu trữ artifact, triển khai lên staging và thực hiện các bài kiểm tra bổ sung. Phiên bản đó có thể được phát hành bất cứ lúc nào.
Tuy nhiên, bước triển khai lên production thường vẫn yêu cầu sự phê duyệt của con người hoặc một thao tác phát hành có chủ đích.
Ví dụ, nhóm phát triển Website bán hàng triển khai tính năng thanh toán mới lên staging. Sau khi bộ phận kiểm thử xác nhận tính năng hoạt động chính xác, người có thẩm quyền phê duyệt việc phát hành lên production.
Cách tiếp cận này phù hợp với những hệ thống cần kiểm soát chặt chẽ việc phát hành, chẳng hạn ứng dụng doanh nghiệp, nền tảng thanh toán hoặc hệ thống có yêu cầu phê duyệt trước khi thay đổi.
3.2. Continuous Deployment
Continuous Deployment, hay triển khai liên tục, tự động đưa các thay đổi lên production sau khi chúng vượt qua tất cả điều kiện kiểm tra và quy tắc bảo vệ đã thiết lập.
Quy trình không dừng lại ở bước chuẩn bị phần mềm sẵn sàng phát hành. Hệ thống sẽ tiếp tục triển khai mà không cần người vận hành phê duyệt riêng cho từng thay đổi.
Ví dụ, lập trình viên sửa một lỗi nhỏ trong chức năng tìm kiếm sản phẩm. Sau khi commit được gửi lên repository, pipeline tự động kiểm tra mã nguồn, chạy test, build và triển khai phiên bản mới lên production. Nếu tất cả bước đều thành công, người dùng có thể sử dụng phiên bản cập nhật mà không cần thao tác phát hành thủ công.
Continuous Deployment yêu cầu hệ thống kiểm thử đáng tin cậy, cơ chế giám sát tốt, quy trình rollback rõ ràng và khả năng phát hiện sự cố nhanh chóng.
3.3. So sánh Continuous Delivery và Continuous Deployment
| Tiêu chí | Continuous Delivery | Continuous Deployment |
|---|---|---|
| Tự động build và test | Có | Có |
| Chuẩn bị phiên bản phát hành | Có | Có |
| Tự động triển khai lên staging | Có thể | Có thể |
| Phê duyệt thủ công trước production | Thường có | Không cần cho từng lần triển khai |
| Triển khai production | Khi được phê duyệt | Tự động khi đủ điều kiện |
| Mức độ tự động hóa phát hành | Cao | Cao hơn ở bước production |
| Yêu cầu kiểm soát rủi ro | Cao | Rất cao |
Điểm cần nhớ là cả hai mô hình đều có thể sử dụng cùng một pipeline. Sự khác biệt nằm ở bước cuối cùng: Continuous Delivery giữ quyền quyết định phát hành ở một bước phê duyệt, còn Continuous Deployment tự động hoàn tất việc phát hành khi các điều kiện được đáp ứng.
4. Quy trình CI/CD Pipeline
CI/CD Pipeline là chuỗi các bước tự động được thực thi để chuyển đổi mã nguồn thành một phiên bản phần mềm có thể kiểm thử, triển khai và sử dụng.
Mỗi bước trong pipeline có một nhiệm vụ cụ thể. Kết quả của bước trước sẽ trở thành đầu vào cho bước tiếp theo. Nếu một bước quan trọng thất bại, pipeline có thể dừng lại để ngăn phiên bản lỗi tiếp tục đi đến môi trường production.
Một pipeline phổ biến có thể được chia thành các giai đoạn sau.
4.1. Source Code Management
Đây là giai đoạn quản lý mã nguồn và tiếp nhận các thay đổi từ lập trình viên.
Các công cụ như Git, GitHub, GitLab và Bitbucket cho phép lưu trữ lịch sử thay đổi, tạo nhánh, hợp nhất mã nguồn và quản lý Pull Request.
Pipeline có thể được kích hoạt bởi những sự kiện như:
-
Một commit mới được đẩy lên repository.
-
Một Pull Request được tạo hoặc cập nhật.
-
Một thay đổi được hợp nhất vào nhánh
main. -
Một bản release hoặc Git tag được tạo.
-
Một lịch chạy định kỳ được kích hoạt.
-
Người vận hành yêu cầu chạy thủ công.
Việc lựa chọn sự kiện kích hoạt ảnh hưởng trực tiếp đến cách pipeline vận hành. Chẳng hạn, kiểm tra mã nguồn trên Pull Request giúp phát hiện lỗi trước khi hợp nhất, trong khi triển khai production thường chỉ được phép thực hiện từ nhánh hoặc phiên bản đã được bảo vệ.
4.2. Build
Build là quá trình chuyển đổi mã nguồn và các tài nguyên liên quan thành sản phẩm có thể chạy hoặc triển khai.
Tùy loại dự án, build có thể bao gồm:
-
Biên dịch mã nguồn.
-
Kiểm tra kiểu dữ liệu.
-
Bundle JavaScript.
-
Biên dịch ứng dụng mobile.
-
Tạo Docker image.
-
Đóng gói thư viện.
-
Tạo tệp tài nguyên phục vụ production.
Ví dụ, với một ứng dụng React sử dụng Vite, lệnh npm run build sẽ tạo ra các tệp phục vụ triển khai trong thư mục dist.
Với dự án Flutter, lệnh flutter build apk tạo gói APK dành cho Android, trong khi flutter build appbundle tạo Android App Bundle.
Đối với Backend Node.js sử dụng TypeScript, bước build thường chuyển các tệp TypeScript thành JavaScript để ứng dụng có thể chạy trong môi trường Node.js.
Build thành công cho thấy quá trình tạo sản phẩm hoàn tất, nhưng không có nghĩa toàn bộ chức năng của ứng dụng đã hoạt động chính xác. Vì vậy, build cần kết hợp với các bước kiểm thử.
4.3. Automated Testing
Automated Testing là giai đoạn chạy các bài kiểm thử tự động nhằm xác minh hành vi của phần mềm.
Các loại kiểm thử thường được sử dụng gồm:
-
Unit Testing: Kiểm tra từng hàm, phương thức hoặc đơn vị logic riêng lẻ.
-
Integration Testing: Kiểm tra sự tương tác giữa các thành phần, chẳng hạn API với database.
-
API Testing: Xác minh request, response, mã trạng thái và dữ liệu trả về.
-
End-to-End Testing: Kiểm tra luồng sử dụng hoàn chỉnh từ góc nhìn người dùng.
-
Regression Testing: Phát hiện lỗi mới làm ảnh hưởng đến chức năng đã hoạt động trước đó.
-
Security Testing: Kiểm tra các rủi ro bảo mật theo những quy tắc và công cụ được tích hợp.
Không phải dự án nào cũng cần tất cả các loại kiểm thử ngay từ đầu. Một dự án nhỏ có thể bắt đầu với lint, unit test và build, sau đó bổ sung integration test hoặc E2E test khi hệ thống phát triển.
Điều quan trọng là các bài kiểm thử phải có khả năng chạy tự động và trả về kết quả đủ rõ ràng để pipeline quyết định có tiếp tục hay không.
4.4. Artifact và Package
Sau khi build và kiểm thử thành công, hệ thống có thể tạo ra artifact, tức sản phẩm đầu ra được lưu trữ để sử dụng ở các giai đoạn tiếp theo.
Artifact có thể là:
-
Tệp ZIP chứa ứng dụng.
-
Thư mục build của Website.
-
Tệp JAR hoặc WAR của ứng dụng Java.
-
Tệp APK hoặc AAB của Android.
-
Docker image.
-
Package của thư viện.
-
Các tệp cấu hình hoặc tài nguyên đã được đóng gói.
Artifact nên được quản lý theo phiên bản để có thể xác định chính xác phần mềm nào đã được kiểm thử và triển khai.
Ví dụ, thay vì build lại ứng dụng một lần cho staging và một lần khác cho production, nhóm có thể build một artifact duy nhất, kiểm thử artifact đó trên staging rồi quảng bá chính artifact đó lên production. Cách này giảm nguy cơ hai môi trường chạy những sản phẩm khác nhau dù được cho là cùng một phiên bản.
4.5. Deployment
Deployment là quá trình đưa phần mềm đến một môi trường cụ thể.
Các môi trường thường gặp gồm:
-
Development: Môi trường phát triển, phục vụ lập trình và kiểm tra ban đầu.
-
Testing/QA: Môi trường kiểm thử chất lượng.
-
Staging: Môi trường gần với production, dùng để xác minh trước khi phát hành.
-
Production: Môi trường phục vụ người dùng thực tế.
Việc triển khai có thể được thực hiện bằng cách tải tệp lên máy chủ, cập nhật Docker container, triển khai lên Kubernetes, cập nhật dịch vụ Cloud hoặc phát hành ứng dụng qua nền tảng phân phối tương ứng.
Deployment không chỉ đơn giản là sao chép mã nguồn. Quy trình thực tế còn có thể bao gồm cấu hình biến môi trường, kiểm tra kết nối database, chạy migration, khởi động dịch vụ và xác nhận ứng dụng sẵn sàng nhận yêu cầu.
4.6. Monitoring và Feedback
Sau khi triển khai, hệ thống cần được giám sát để xác định phiên bản mới có hoạt động ổn định hay không.
Các thông tin thường được theo dõi gồm:
-
Tỷ lệ request thành công và thất bại.
-
Thời gian phản hồi API.
-
CPU, RAM và dung lượng lưu trữ.
-
Số lượng lỗi ứng dụng.
-
Trạng thái kết nối database.
-
Tỷ lệ giao dịch hoặc nghiệp vụ thành công.
-
Trạng thái health check sau triển khai.
Nếu phát hiện vấn đề, nhóm phát triển có thể nhận thông báo, điều tra nguyên nhân, rollback phiên bản hoặc triển khai bản sửa lỗi.
Như vậy, CI/CD không nên kết thúc ngay sau khi hệ thống báo triển khai thành công. Phản hồi từ môi trường thực tế là cơ sở để cải thiện cả phần mềm lẫn pipeline trong những lần phát hành tiếp theo.
5. Cấu trúc và thành phần của CI/CD Pipeline
Một pipeline thường bao gồm nhiều thành phần phối hợp với nhau để tự động hóa quá trình phát triển phần mềm.
5.1. Repository
Repository là nơi lưu trữ mã nguồn và lịch sử thay đổi. GitHub, GitLab và Bitbucket đều có thể đóng vai trò là nơi khởi đầu của pipeline.
Repository cung cấp thông tin về commit, nhánh, tag và Pull Request. Pipeline dựa vào các thông tin này để xác định phiên bản cần kiểm tra hoặc triển khai.
5.2. Trigger
Trigger là sự kiện khiến pipeline bắt đầu chạy.
Ví dụ:
-
push: Chạy khi có mã nguồn mới được đẩy lên. -
pull_request: Chạy khi Pull Request được tạo hoặc cập nhật. -
schedule: Chạy theo lịch. -
workflow_dispatch: Cho phép chạy thủ công trong GitHub Actions. -
Tag hoặc release: Chạy quy trình phát hành phiên bản.
Việc thiết kế trigger hợp lý giúp tránh chạy những công việc tốn tài nguyên không cần thiết, đồng thời bảo đảm các thay đổi quan trọng luôn được kiểm tra.
5.3. Runner hoặc Agent
Runner là môi trường thực thi các công việc của pipeline.
Runner có thể là máy ảo do nhà cung cấp CI/CD quản lý, máy chủ do doanh nghiệp tự vận hành hoặc một môi trường container chuyên dụng.
Ví dụ, GitHub-hosted runner cung cấp các môi trường Linux, Windows và macOS để thực thi workflow. Self-hosted runner cho phép doanh nghiệp chủ động kiểm soát phần cứng, mạng nội bộ và các công cụ được cài đặt.
Runner chịu trách nhiệm thực hiện những lệnh được khai báo, chẳng hạn cài dependency, chạy test, build và đóng gói ứng dụng.
5.4. Job và Step
Trong nhiều hệ thống CI/CD, job là một nhóm công việc được thực thi trên runner, còn step là từng hành động bên trong job.
Ví dụ, một job kiểm thử có thể chứa các step:
-
Checkout mã nguồn.
-
Cài đặt Node.js.
-
Cài dependency.
-
Chạy lint.
-
Chạy unit test.
-
Build ứng dụng.
Các job có thể phụ thuộc lẫn nhau hoặc chạy song song khi không có phụ thuộc bắt buộc. Chẳng hạn, lint và unit test có thể chạy đồng thời để rút ngắn thời gian pipeline.
5.5. Artifact Registry
Artifact Registry là nơi lưu trữ những sản phẩm được tạo ra trong quá trình build.
Đối với Docker, hệ thống có thể sử dụng Docker Hub, GitHub Container Registry hoặc một registry riêng của doanh nghiệp. Với package, hệ thống có thể sử dụng npm registry hoặc các kho lưu trữ package tương ứng.
Việc lưu trữ artifact theo phiên bản giúp triển khai nhất quán, truy vết nguồn gốc sản phẩm và hỗ trợ rollback.
5.6. Secrets và Environment Variables
Pipeline thường cần các thông tin cấu hình như API key, token truy cập, thông tin xác thực registry hoặc thông tin kết nối dịch vụ.
Các thông tin này phải được quản lý thông qua cơ chế secrets của nền tảng CI/CD hoặc một hệ thống quản lý bí mật chuyên dụng. Không nên ghi trực tiếp mật khẩu hoặc token vào mã nguồn hay tệp workflow được lưu trong repository.
Environment variables được sử dụng để truyền cấu hình cho các bước thực thi, nhưng cần phân biệt biến cấu hình thông thường với thông tin nhạy cảm. Không phải mọi biến môi trường đều tự động được bảo vệ như secret.
6. Phân biệt CI/CD với DevOps
CI/CD và DevOps có quan hệ mật thiết nhưng không phải là hai thuật ngữ đồng nghĩa.
DevOps là cách tiếp cận kết hợp phát triển phần mềm (Development) và vận hành hệ thống (Operations), hướng đến tăng cường phối hợp, tự động hóa, phản hồi nhanh và cải thiện liên tục.
CI/CD là một trong những thực hành kỹ thuật quan trọng hỗ trợ mục tiêu đó.
| Tiêu chí | DevOps | CI/CD |
|---|---|---|
| Bản chất | Văn hóa, phương pháp và tập hợp thực hành | Quy trình tích hợp, kiểm thử, phân phối và triển khai |
| Phạm vi | Phát triển, vận hành, giám sát và cải tiến | Tập trung vào pipeline phần mềm |
| Thành phần | Con người, quy trình, công cụ và hệ thống | Trigger, runner, job, test, artifact và deployment |
| Mục tiêu | Tăng hiệu quả phối hợp và độ tin cậy khi vận hành | Tự động hóa việc kiểm tra và phát hành |
| Công cụ tiêu biểu | Docker, Kubernetes, Terraform, hệ thống monitoring | GitHub Actions, GitLab CI/CD, Jenkins |
Một doanh nghiệp có thể sử dụng CI/CD nhưng chưa triển khai đầy đủ văn hóa DevOps. Ngược lại, một tổ chức theo đuổi DevOps thường áp dụng CI/CD để giảm thao tác thủ công và rút ngắn vòng đời phát triển.
Ngoài CI/CD, DevOps còn bao gồm quản lý hạ tầng dưới dạng mã (Infrastructure as Code), quản lý cấu hình, giám sát hệ thống, quản lý sự cố, bảo mật và tối ưu hóa quy trình vận hành.
7. Các công cụ CI/CD phổ biến
Việc lựa chọn công cụ phụ thuộc vào hệ sinh thái công nghệ, hạ tầng triển khai, yêu cầu bảo mật và mức độ phức tạp của dự án.
GitHub Actions
Tích hợp trực tiếp với GitHub, sử dụng workflow YAML để tự động hóa build, test và deploy. Phù hợp với các dự án cá nhân, nhóm nhỏ và nhiều dự án doanh nghiệp đang lưu trữ mã nguồn trên GitHub.
GitLab CI/CD
Cung cấp pipeline tích hợp với GitLab repository, merge request, registry và các chức năng DevSecOps. Cấu hình pipeline thường được đặt trong tệp .gitlab-ci.yml.
Jenkins
Máy chủ tự động hóa mã nguồn mở, hỗ trợ pipeline thông qua Jenkinsfile và hệ sinh thái plugin. Thích hợp khi tổ chức cần tùy biến sâu hoặc tự quản lý hạ tầng CI/CD.
CircleCI
Nền tảng tự động hóa quy trình build, test và deploy, hỗ trợ các môi trường thực thi khác nhau cùng những cơ chế tối ưu thời gian pipeline.
Azure Pipelines
Hỗ trợ xây dựng và triển khai ứng dụng trên nhiều nền tảng, tích hợp với hệ sinh thái Azure DevOps và nhiều loại repository.
Không có công cụ nào luôn tốt nhất cho mọi dự án. Nếu mã nguồn đã được lưu trên GitHub và nhu cầu chủ yếu là chạy test, build và deploy, GitHub Actions thường là điểm khởi đầu thuận tiện. Với hệ thống lớn cần kiểm soát hạ tầng riêng hoặc có những quy trình đặc thù, Jenkins và các nền tảng self-hosted có thể phù hợp hơn.
8. Xây dựng CI/CD thực tế với GitHub Actions
Để hiểu rõ cách CI/CD hoạt động, có thể xây dựng một pipeline đơn giản cho ứng dụng Node.js. Ví dụ này sẽ tự động cài dependency, kiểm tra mã nguồn, chạy test và build mỗi khi có Pull Request hoặc khi lập trình viên đẩy mã lên nhánh main.
8.1. Cấu trúc dự án
Giả sử dự án có cấu trúc như sau:
my-project/
├── src/
│ └── index.js
├── test/
│ └── index.test.js
├── package.json
├── package-lock.json
└── .github/
└── workflows/
└── ci.yml
Thư mục .github/workflows/ là nơi GitHub Actions tìm các tệp workflow được cấu hình bằng YAML.
8.2. Khai báo scripts trong package.json
Tệp package.json cần định nghĩa những lệnh mà pipeline sẽ sử dụng. Ví dụ:
{
"name": "my-project",
"version": "1.0.0",
"private": true,
"scripts": {
"lint": "eslint src test",
"test": "node --test",
"build": "node --check src/index.js"
},
"devDependencies": {
"eslint": "^9.0.0"
}
}
Đây là ví dụ minh họa cho một dự án Node.js đơn giản. Với ứng dụng thực tế, lệnh build cần được thay thế bằng lệnh build tương ứng của framework đang sử dụng.
Lưu ý: nếu chọn cấu hình ESLint 9 như trên, dự án cần có tệp cấu hình phù hợp, chẳng hạn eslint.config.js. Các script chỉ hoạt động khi công cụ và cấu hình tương ứng đã được thiết lập đầy đủ.
8.3. Tạo workflow CI
Tạo tệp .github/workflows/ci.yml với nội dung sau:
name: CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
permissions:
contents: read
jobs:
test:
name: Test and Build
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Run lint
run: npm run lint
- name: Run tests
run: npm test
- name: Build application
run: npm run build
Trong ví dụ này, pipeline gồm một job tên test với các bước được thực hiện tuần tự.
-
on: Khai báo sự kiện kích hoạt workflow. -
push: Chạy khi có thay đổi được đẩy lên nhánhmain. -
pull_request: Chạy khi có Pull Request hướng đến nhánhmain. -
permissions: Giới hạn quyền truy cập của workflow ở mức chỉ đọc nội dung repository. -
runs-on: Chọn máy Linux để chạy job. -
actions/checkout: Lấy mã nguồn từ repository. -
actions/setup-node: Cài đặt và cấu hình phiên bản Node.js. -
npm ci: Cài dependency theo lockfile. -
npm run lint: Kiểm tra chất lượng mã nguồn. -
npm test: Chạy các bài kiểm thử. -
npm run build: Thực hiện bước build đã định nghĩa trong dự án.
Nếu một bước thất bại, các bước tiếp theo trong job thường sẽ không chạy, trừ khi được cấu hình điều kiện đặc biệt. Kết quả được hiển thị trực tiếp trong mục Actions của repository GitHub.
Đối với môi trường production, nên tiếp tục ghim các GitHub Actions quan trọng theo commit SHA đã được xác minh và thường xuyên cập nhật phiên bản action để giảm rủi ro bảo mật.
8.4. Kiểm tra kết quả pipeline
Sau khi đẩy mã nguồn lên GitHub:
-
Mở repository của dự án.
-
Chọn tab Actions.
-
Chọn workflow
CI Pipeline. -
Mở lần chạy tương ứng với commit hoặc Pull Request.
-
Xem trạng thái từng bước và đọc log nếu có lỗi.
Thông thường, trạng thái xanh cho biết workflow hoàn tất thành công, còn trạng thái đỏ thể hiện một bước hoặc job đã thất bại.
Tuy nhiên, workflow thành công chỉ xác nhận những điều kiện đã được cấu hình đều vượt qua. Nếu pipeline chưa có integration test, security scan hoặc các kiểm tra nghiệp vụ quan trọng, nó không thể tự chứng minh những khía cạnh đó đều đúng.
9. Triển khai ứng dụng lên Production
Sau khi CI hoạt động ổn định, có thể mở rộng pipeline để tự động triển khai ứng dụng.
Một quy trình triển khai điển hình sẽ có dạng:
1. Push code
GitHub repository
2. CI
Lint, test, build
3. Artifact
Tạo package hoặc Docker image
4. Approval / Release Gate
Kiểm tra điều kiện phát hành nếu cần
5. Deploy
Staging hoặc Production
6. Health Check & Monitoring
Xác nhận ứng dụng hoạt động ổn định
Cần phân biệt việc tự động triển khai với việc bảo đảm triển khai an toàn. Một pipeline production nên có cơ chế xác thực, phân quyền, kiểm tra trạng thái ứng dụng và xử lý tình huống triển khai thất bại.
9.1. Quản lý thông tin đăng nhập
Nếu triển khai lên máy chủ thông qua SSH, pipeline có thể cần khóa riêng, địa chỉ máy chủ và tài khoản triển khai. Những thông tin này phải được lưu trong GitHub Secrets hoặc hệ thống quản lý bí mật phù hợp.
Không nên đặt khóa riêng, mật khẩu hay access token trực tiếp trong tệp YAML.
Nếu nền tảng đích hỗ trợ OpenID Connect (OIDC), có thể sử dụng cơ chế xác thực ngắn hạn thay cho việc lưu trữ các thông tin đăng nhập dài hạn.
9.2. Health Check
Sau khi triển khai, hệ thống nên kiểm tra endpoint sức khỏe của ứng dụng hoặc thực hiện một số kiểm tra chức năng quan trọng.
Ví dụ, với một API cung cấp endpoint /health, quy trình có thể gửi HTTP request để xác nhận dịch vụ phản hồi thành công. Trong hệ thống thực tế, nên kết hợp kiểm tra trạng thái HTTP với các điều kiện khác như khả năng kết nối database hoặc trạng thái phụ thuộc thiết yếu.
Nếu health check thất bại, hệ thống có thể đánh dấu deployment không thành công và kích hoạt quy trình xử lý sự cố đã được định nghĩa.
9.3. Rollback
Rollback là quá trình quay lại phiên bản trước đó khi bản phát hành mới gây ra sự cố.
Ví dụ, phiên bản mới khiến chức năng đặt hàng trả về lỗi. Nhóm vận hành có thể chuyển lưu lượng trở lại phiên bản ổn định trước đó trong khi điều tra nguyên nhân.
Rollback cần được thiết kế từ trước. Đặc biệt, các thay đổi database có thể không tương thích ngược, vì vậy không phải mọi sự cố đều có thể giải quyết chỉ bằng cách quay lại phiên bản ứng dụng cũ.
10. CI/CD với Docker
Docker thường được kết hợp với CI/CD để đóng gói ứng dụng cùng các thành phần cần thiết vào một image. Cách này giúp giảm sự khác biệt giữa môi trường phát triển, kiểm thử và triển khai.
Ví dụ, với ứng dụng Node.js, có thể sử dụng Dockerfile sau:
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:22-alpine AS production
WORKDIR /app
ENV NODE_ENV=production
COPY package*.json ./
RUN npm ci --omit=dev
COPY --from=build /app/src ./src
EXPOSE 3000
CMD ["node", "src/index.js"]
Đây chỉ là cấu trúc minh họa. Dockerfile cần được điều chỉnh theo ứng dụng cụ thể, đặc biệt khi bước build tạo ra thư mục dist, ứng dụng cần các tệp tài nguyên khác hoặc có yêu cầu biên dịch native module.
Pipeline Docker thường thực hiện các công việc:
-
Checkout mã nguồn.
-
Chạy lint và test.
-
Build Docker image.
-
Gắn tag cho image theo phiên bản hoặc commit.
-
Đẩy image lên container registry.
-
Triển khai image lên môi trường đích.
-
Kiểm tra trạng thái dịch vụ.
Khi sử dụng Docker, cần tránh nhúng secret vào image hoặc lưu thông tin nhạy cảm trong các layer. Các dependency và image nền cũng nên được quản lý phiên bản rõ ràng, cập nhật định kỳ và quét lỗ hổng bảo mật.
11. CI/CD trong các loại dự án phần mềm
CI/CD không chỉ dành cho Backend. Mỗi loại dự án có những công việc build, test và deploy khác nhau.
11.1. Website Frontend
Đối với React, Vue, Angular hoặc Next.js, pipeline có thể thực hiện:
-
Cài đặt dependency.
-
Chạy ESLint và kiểm tra TypeScript.
-
Chạy unit test.
-
Build ứng dụng.
-
Kiểm tra artifact.
-
Triển khai lên dịch vụ hosting hoặc máy chủ.
Đối với Website tĩnh, artifact thường là các tệp HTML, CSS, JavaScript và tài nguyên liên quan. Với ứng dụng Next.js có server-side rendering, quy trình triển khai cần phù hợp với cách ứng dụng được vận hành, chẳng hạn Node.js server hoặc nền tảng hỗ trợ Next.js.
11.2. Backend API
Đối với Node.js, NestJS, ASP.NET Core hoặc Spring Boot, pipeline thường có thêm các bước:
-
Build và kiểm tra kiểu dữ liệu.
-
Unit test và integration test.
-
Kiểm tra API.
-
Build Docker image.
-
Quét lỗ hổng dependency và image.
-
Triển khai lên server hoặc nền tảng container.
-
Chạy health check.
Với Backend sử dụng PostgreSQL hoặc SQL Server, các thay đổi schema cần được quản lý bằng migration. Việc chạy migration nên có kiểm soát, sao lưu khi cần và kế hoạch xử lý khi thay đổi không tương thích.
11.3. Flutter và Mobile App
Đối với Flutter, pipeline có thể chạy:
-
flutter pub getđể lấy dependency. -
dart format --output=none --set-exit-if-changed .để kiểm tra định dạng. -
flutter analyzeđể phân tích mã nguồn. -
flutter testđể chạy unit test và widget test. -
flutter build apkhoặcflutter build appbundleđể tạo gói Android.
Đối với iOS, pipeline cần môi trường macOS và các công cụ liên quan đến Xcode để build ứng dụng. Các bước ký ứng dụng và phát hành qua App Store Connect cần được cấu hình riêng.
Một điểm khác biệt là Mobile App không phải lúc nào cũng có thể đưa bản cập nhật trực tiếp đến toàn bộ người dùng chỉ bằng một thao tác deploy. Phiên bản mới còn phụ thuộc vào quá trình ký ứng dụng, kiểm duyệt của cửa hàng và cách người dùng cài đặt bản cập nhật.
11.4. Dự án Data và AI
CI/CD cũng được sử dụng trong các dự án dữ liệu và AI để kiểm soát mã nguồn, kiểm thử pipeline xử lý dữ liệu, xác minh cấu hình mô hình và đóng gói dịch vụ suy luận.
Tùy dự án, quy trình có thể bao gồm kiểm tra chất lượng dữ liệu, đánh giá mô hình, kiểm thử API suy luận và triển khai phiên bản mô hình đã được phê duyệt.
Đối với các mô hình AI, chỉ kiểm tra việc chạy thành công chưa đủ để xác nhận chất lượng. Pipeline nên có những tiêu chí đánh giá phù hợp với bài toán, dữ liệu kiểm thử và yêu cầu nghiệp vụ.
12. Các phương pháp nâng cao độ tin cậy của CI/CD
Một pipeline tốt không chỉ chạy tự động mà còn cần bảo đảm tính nhất quán, an toàn và khả năng khôi phục.
12.1. Giữ pipeline nhanh và ổn định
Pipeline quá chậm có thể khiến lập trình viên trì hoãn việc tích hợp mã nguồn hoặc bỏ qua phản hồi. Vì vậy, nên ưu tiên những bước kiểm tra nhanh trước, chẳng hạn lint, type checking và unit test, rồi thực hiện các bước nặng hơn khi phù hợp.
Có thể sử dụng cache dependency, chạy các job độc lập song song và tránh build lại cùng một artifact không cần thiết.
Tuy nhiên, cache phải được cấu hình đúng để không sử dụng nhầm dependency hoặc kết quả cũ. Một pipeline vẫn cần có khả năng chạy sạch mà không phụ thuộc vào trạng thái ngẫu nhiên từ lần chạy trước.
12.2. Bảo vệ nhánh chính
Nhánh main thường được bảo vệ bằng các quy tắc như:
-
Yêu cầu Pull Request trước khi hợp nhất.
-
Bắt buộc các CI check quan trọng phải thành công.
-
Yêu cầu review từ thành viên phù hợp.
-
Hạn chế quyền push trực tiếp.
-
Yêu cầu giải quyết xung đột trước khi merge.
Các quy tắc này giúp hạn chế việc mã nguồn chưa được kiểm tra đi vào nhánh phát hành.
12.3. Quản lý phiên bản và truy vết
Mỗi artifact nên gắn với một phiên bản hoặc commit cụ thể. Khi xảy ra sự cố, nhóm có thể xác định mã nguồn nào đã tạo ra sản phẩm đang chạy, những kiểm tra nào đã được thực hiện và phiên bản trước đó là gì.
Đối với hệ thống quan trọng, có thể bổ sung SBOM (Software Bill of Materials), chữ ký artifact và thông tin provenance để tăng khả năng truy xuất nguồn gốc và xác minh tính toàn vẹn của sản phẩm.
12.4. Tích hợp bảo mật vào pipeline
DevSecOps đưa các hoạt động bảo mật vào quy trình phát triển và vận hành thay vì chỉ kiểm tra ở giai đoạn cuối.
Những bước thường được tích hợp gồm:
-
SAST: Phân tích mã nguồn tĩnh.
-
SCA: Kiểm tra thư viện và dependency.
-
Secret scanning: Phát hiện thông tin bí mật bị đưa vào repository.
-
Container scanning: Kiểm tra lỗ hổng trong image.
-
Kiểm tra cấu hình hạ tầng.
-
DAST: Kiểm tra bảo mật ứng dụng đang chạy khi phù hợp.
Không phải cảnh báo nào cũng có mức độ nghiêm trọng giống nhau. Nhóm nên xác định tiêu chí chặn pipeline, quy trình xử lý ngoại lệ và người chịu trách nhiệm khắc phục để bảo đảm kiểm tra bảo mật có hiệu quả thực tế.
12.5. Sử dụng chiến lược triển khai an toàn
Với hệ thống có nhiều người dùng, có thể áp dụng những chiến lược triển khai giúp giảm ảnh hưởng khi phiên bản mới có lỗi.
-
Rolling Deployment: Thay thế các instance theo từng đợt.
-
Blue-Green Deployment: Duy trì hai môi trường, chuyển lưu lượng sang môi trường mới sau khi kiểm tra.
-
Canary Deployment: Phát hành cho một phần lưu lượng trước khi mở rộng.
-
Feature Flags: Bật hoặc tắt chức năng thông qua cấu hình mà không nhất thiết phải triển khai lại toàn bộ ứng dụng.
Việc lựa chọn chiến lược phụ thuộc vào kiến trúc hệ thống, khả năng quản lý lưu lượng, yêu cầu sẵn sàng và chi phí vận hành.
13. Những lỗi thường gặp khi xây dựng CI/CD
Một số vấn đề phổ biến có thể khiến pipeline hoạt động không ổn định hoặc tạo ra rủi ro cho hệ thống.
Chỉ kiểm tra build mà không chạy test: Ứng dụng có thể build thành công nhưng vẫn chứa lỗi nghiệp vụ. Cần bổ sung các bài kiểm thử phù hợp.
Sử dụng cấu hình khác nhau giữa các môi trường: Ứng dụng chạy tốt ở staging nhưng lỗi ở production do khác phiên bản runtime, biến môi trường hoặc dependency. Nên chuẩn hóa môi trường và quản lý cấu hình rõ ràng.
Lưu secret trực tiếp trong mã nguồn: Điều này có thể làm lộ thông tin truy cập và gây ảnh hưởng nghiêm trọng. Secret cần được quản lý riêng, hạn chế quyền truy cập và luân chuyển khi cần.
Tự động triển khai mọi nhánh lên production: Nếu không có điều kiện bảo vệ, mã nguồn chưa được review có thể được phát hành. Cần giới hạn trigger và quyền triển khai.
Không có kế hoạch rollback: Khi phiên bản mới gây lỗi, nhóm có thể mất nhiều thời gian khôi phục. Cần xác định trước phương án quay lại phiên bản ổn định và xử lý các thay đổi database liên quan.
Bỏ qua monitoring: Pipeline báo deploy thành công không đồng nghĩa hệ thống vận hành bình thường. Cần theo dõi sức khỏe ứng dụng sau triển khai.
Lạm dụng công cụ hoặc plugin: Quá nhiều bước kiểm tra trùng lặp làm pipeline phức tạp và chậm. Nên đánh giá giá trị của từng bước, loại bỏ công việc dư thừa và duy trì tài liệu cấu hình.
14. Kết luận
CI/CD là nền tảng quan trọng giúp tự động hóa vòng đời phát triển và phát hành phần mềm. CI tập trung vào việc tích hợp mã nguồn thường xuyên và kiểm tra tự động; Continuous Delivery bảo đảm phần mềm luôn sẵn sàng phát hành; Continuous Deployment tự động triển khai những thay đổi đã đáp ứng đầy đủ điều kiện lên production.
Việc áp dụng CI/CD giúp giảm thao tác thủ công, phát hiện lỗi sớm, chuẩn hóa quy trình làm việc và tăng khả năng truy vết phiên bản. Tuy nhiên, hiệu quả của CI/CD không chỉ phụ thuộc vào công cụ mà còn nằm ở chất lượng kiểm thử, quản lý cấu hình, bảo mật, giám sát và khả năng khôi phục khi xảy ra sự cố.
Đối với lập trình viên, bắt đầu với một pipeline đơn giản trên GitHub Actions, sau đó mở rộng sang Docker và deployment thực tế là cách tiếp cận phù hợp. Khi hiểu rõ từng thành phần, CI/CD sẽ trở thành một kỹ năng hữu ích trong cả phát triển Frontend, Backend, Mobile và vận hành hệ thống.








Khoá học lập trình game con rắn cho trẻ em




