Tại sao phải Quan tâm đến CI/CD Pipeline?
Bạn vừa đẩy (push) một tính năng mới. Điều gì xảy ra tiếp theo? Nếu quy trình của bạn bao gồm việc SSH thủ công vào máy chủ, kéo code, chạy kiểm thử, và khởi động lại dịch vụ, thì bạn đang sống trên bờ vực rủi ro. Quy trình thủ công đó chậm chạp, dễ xảy ra lỗi và rất tốn thời gian. Một pipeline CI/CD (Tích hợp liên tục/Triển khai liên tục – Continuous Integration/Continuous Deployment) sẽ tự động hóa toàn bộ quy trình công việc này. Nó tạo ra một cầu nối đáng tin cậy, có thể lặp lại từ lệnh `git push` của bạn đến một ứng dụng đang chạy trực tiếp.
Chúng ta sẽ tập trung vào GitLab CI vì nó được tích hợp trực tiếp vào GitLab. Không cần dịch vụ của bên thứ ba hay các tích hợp phức tạp. Nếu code của bạn nằm trên GitLab, bạn đã có mọi thứ cần thiết để bắt đầu. Toàn bộ quy trình được kiểm soát bởi một tệp duy nhất trong repository của bạn: .gitlab-ci.yml. Khi bạn đẩy code mới, GitLab sẽ tìm tệp này và sử dụng GitLab Runner để thực thi quy trình làm việc tự động của bạn.
Bước 1: Cài đặt GitLab Runner
GitLab Runner là thành phần chính trong quy trình CI/CD của bạn. Nó là một agent gọn nhẹ mà bạn cài đặt trên máy chủ, có nhiệm vụ nhận và chạy các job bạn đã định nghĩa. Mặc dù GitLab cung cấp các runner chia sẻ, tự động co giãn, việc cài đặt runner của riêng bạn cho phép bạn kiểm soát hoàn toàn môi trường và giữ toàn bộ quy trình trong hạ tầng của chính mình. Điều này lý tưởng cho các dự án cần các dependency cụ thể hoặc yêu cầu bảo mật cao.
Hãy cài đặt một runner trên máy chủ Debian hoặc Ubuntu.
1. Cài đặt Gói GitLab Runner
Đầu tiên, thêm repository chính thức của GitLab và cài đặt gói runner với vài lệnh.
# Tải xuống và thêm script repository
curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash
# Cài đặt phiên bản mới nhất của GitLab Runner
sudo apt-get install gitlab-runner -y
2. Đăng ký Runner với Dự án của Bạn
Tiếp theo, bạn cần liên kết runner đã cài đặt với dự án GitLab của mình. Bước quan trọng này cho runner biết nơi để lắng nghe các job mới.
Trong dự án GitLab của bạn, đi đến Settings > CI/CD và mở rộng mục Runners. Bạn sẽ tìm thấy URL điều phối (coordinator URL) và một mã token đăng ký (registration token) cần cho bước tiếp theo. Hãy giữ trang này mở.
Bây giờ, chạy lệnh đăng ký trên máy chủ của bạn:
sudo gitlab-runner register
Bạn sẽ được hỏi một vài chi tiết:
- Enter the GitLab instance URL: Đây là URL từ trang Runners (ví dụ: https://gitlab.com/).
- Enter the registration token: Sao chép và dán mã token từ cùng trang đó.
- Enter a description for the runner: Dùng một tên có tính mô tả, như “Runner cho dự án của tôi”.
- Enter tags for the runner: Các tag cho phép bạn gán các job cụ thể cho runner này. Ví dụ, bạn có thể tag runner này là `production` để đảm bảo chỉ nó xử lý các job triển khai. Bạn có thể để trống mục này.
- Enter an executor: Đây là lựa chọn quan trọng nhất, vì nó xác định môi trường nơi các job của bạn thực thi. Các lựa chọn chính của bạn là `shell`, `docker`, hoặc `kubernetes`. Chúng tôi thực sự khuyên dùng
docker. Nó tạo ra một container mới, biệt lập cho mỗi job, đảm bảo một môi trường sạch sẽ và ngăn ngừa xung đột dependency. Nếu bạn chọn `docker`, bạn sẽ được hỏi về một image mặc định (ví dụ: `node:18` hoặc `python:3.9`). Bạn có thể bắt đầu với một image tối giản như `alpine:latest` và chỉ định image cho từng job sau.
Sau khi hoàn tất các bước trên, runner đã được cài đặt, đăng ký và sẵn sàng làm việc.
Bước 2: Cấu hình Pipeline của bạn với .gitlab-ci.yml
Khi runner đã sẵn sàng chờ lệnh, đã đến lúc viết chúng. Bạn định nghĩa toàn bộ pipeline của mình trong một tệp duy nhất có tên .gitlab-ci.yml, đặt ở thư mục gốc của repository.
Hiểu về Cấu trúc: Stages và Jobs
Pipeline được tổ chức thành các `stages` (giai đoạn), và các stage chứa các `jobs` (công việc). Tất cả các job trong cùng một stage sẽ chạy song song, trong khi các stage sẽ chạy tuần tự. Một cấu trúc kinh điển và hiệu quả là `build` -> `test` -> `deploy`.
Đây là một ví dụ đơn giản định nghĩa các stage này và bao gồm một job giữ chỗ cho mỗi stage.
# .gitlab-ci.yml
stages:
- build
- test
- deploy
build_job:
stage: build
script:
- echo "Job này xây dựng dự án."
- echo "Ví dụ, bạn có thể chạy 'npm install' hoặc 'composer install' ở đây."
run_tests:
stage: test
script:
- echo "Job này chạy các bài kiểm thử."
- echo "Ví dụ, chạy 'pytest' hoặc 'npm test'."
deploy_job:
stage: deploy
script:
- echo "Job này triển khai dự án lên máy chủ."
- echo "Bạn có thể dùng 'scp', 'rsync', hoặc một lệnh SSH ở đây."
Khi bạn commit tệp này, GitLab sẽ khởi động pipeline đầu tiên của bạn. Nó sẽ chạy `build_job`, và nếu thành công, nó sẽ chạy `run_tests`, và cuối cùng là `deploy_job`.
Một ví dụ Thực tế: Ứng dụng Node.js
Hãy tạo một pipeline thực tế hơn cho một ứng dụng Node.js. Chúng ta sẽ tận dụng Docker executor và định nghĩa một image Node.js cụ thể cho các job của mình.
# .gitlab-ci.yml
default:
image: node:18 # Sử dụng Node.js 18 làm mặc định cho tất cả các job
stages:
- build
- test
- deploy
install_dependencies:
stage: build
script:
- echo "Đang cài đặt các dependency của máy chủ..."
- npm install
artifacts:
paths:
- node_modules/
expire_in: 1 hour
test_app:
stage: test
script:
- echo "Đang chạy kiểm thử..."
- npm test
needs:
- install_dependencies
deploy_to_production:
stage: deploy
script:
- echo "Đang triển khai lên máy chủ production..."
# Một script triển khai thực tế sẽ sử dụng SSH key được lưu trong các biến của GitLab
- ssh [email protected] 'cd /path/to/app && git pull && pm2 restart app_name'
environment:
name: production
when: on_success
rules:
- if: $CI_COMMIT_BRANCH == 'main'
Hãy phân tích các từ khóa mới trong ví dụ này:
default: image:thiết lập một Docker image mặc định, vì vậy bạn không cần phải chỉ định `image: node:18` trên mỗi job.artifacts:Đây là một khái niệm quan trọng. Nó lưu các `paths` được chỉ định (trong trường hợp này là thư mục `node_modules/`) sau khi một job hoàn thành và cung cấp chúng cho các job ở các stage sau. Điều này có nghĩa là bạn không cần phải chạy `npm install` nhiều lần.needs:Điều này tạo ra một sự phụ thuộc, đảm bảo job `test_app` chỉ bắt đầu sau khi `install_dependencies` đã hoàn thành thành công.environment:Giúp bạn theo dõi các lần triển khai trong giao diện của GitLab, tạo ra một bản ghi về code nào đã được triển khai và khi nào.rules:Đây là cách hiện đại để kiểm soát khi nào một job chạy. Ở đây, chúng tôi đảm bảo job triển khai chỉ chạy khi có commit vào nhánh `main`, ngăn chặn việc triển khai tình cờ từ các nhánh tính năng.
Một lưu ý quan trọng về việc triển khai: không bao giờ hardcode các thông tin nhạy cảm như SSH key trong tệp .gitlab-ci.yml của bạn. Đây là một lỗ hổng bảo mật cực lớn. Thay vào đó, hãy sử dụng các biến CI/CD được tích hợp sẵn của GitLab, có trong Settings > CI/CD > Variables. Bạn có thể lưu trữ an toàn một private SSH key dưới dạng biến loại ‘File’. Script của bạn sau đó có thể sử dụng biến này để xác thực mà không để lộ key trong repository hoặc log. Thực hành này là một bước không thể thiếu cho các pipeline ở cấp độ production.
Bước 3: Xác minh và Giám sát Pipeline của bạn
Sau khi đã commit tệp .gitlab-ci.yml, làm thế nào để thấy nó hoạt động? Điều hướng đến mục CI/CD > Pipelines trong dự án GitLab của bạn. Màn hình này là trung tâm điều khiển cho quá trình tự động hóa của bạn.
Bạn sẽ thấy một danh sách tất cả các lần chạy pipeline, mỗi lần có một trạng thái: pending (chờ xử lý), running (đang chạy), passed (thành công), hoặc failed (thất bại). Bạn có thể nhấp vào bất kỳ pipeline nào để xem các stage và job của nó. Nếu một job thất bại, một dấu ‘X’ màu đỏ sẽ chỉ cho bạn chính xác vấn đề ở đâu. Nhấp vào job thất bại sẽ đưa bạn trực tiếp đến log output, nơi bạn có thể tìm thấy thông báo lỗi để gỡ lỗi. Vòng lặp phản hồi là ngay lập tức—một trong những lợi thế chính của một quy trình CI/CD được triển khai tốt.
Khi mọi thứ đã chạy trơn tru, bạn có thể thêm huy hiệu trạng thái pipeline vào tệp `README.md` của dự án để hiển thị trạng thái build. Bạn có thể lấy mã nhúng cho huy hiệu này từ Settings > CI/CD > General pipelines.

