Bạn vừa merge một pull request, vài phút sau nhận được tin nhắn: "Production lỗi rồi!". Hoá ra có người quên chạy test trước khi đẩy code. Những sự cố kiểu này rất phổ biến khi quy trình kiểm tra và triển khai còn phụ thuộc vào con người. CI/CD (Continuous Integration / Continuous Delivery) giúp tự động hoá các bước đó, để mỗi thay đổi đều được kiểm tra nhất quán trước khi đến tay người dùng. Với dự án đặt trên GitHub, GitHub Actions là cách nhanh nhất để bắt đầu mà không cần dựng thêm server CI riêng.
CI và CD khác nhau thế nào?
- Continuous Integration (CI): mỗi lần đẩy code hoặc mở pull request, hệ thống tự động cài đặt, chạy lint, test và build. Mục tiêu là phát hiện lỗi sớm, khi thay đổi còn nhỏ và dễ sửa.
- Continuous Delivery / Deployment (CD): sau khi CI thành công, code được đóng gói và triển khai tự động lên môi trường staging hoặc production. Delivery thường có bước phê duyệt thủ công trước production, còn Deployment triển khai hoàn toàn tự động.
Các khái niệm cơ bản trong GitHub Actions
- Workflow: một quy trình tự động, khai báo bằng tệp YAML trong thư mục
.github/workflows/. - Event: sự kiện kích hoạt workflow, ví dụ
push,pull_request, lịch hẹn giờ hay kích hoạt thủ côngworkflow_dispatch. - Job: một nhóm bước chạy trên cùng một máy (runner). Các job mặc định chạy song song, có thể khai báo phụ thuộc bằng
needs. - Step: từng lệnh shell hoặc một action có sẵn.
- Runner: máy ảo thực thi job, có thể do GitHub cung cấp hoặc tự host.
Workflow CI đầu tiên
Tạo tệp .github/workflows/ci.yml:
name: CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [22.x, 24.x]
steps:
- uses: actions/checkout@v6
- uses: actions/setup-node@v7
with: { node-version: "${{ matrix.node-version }}", cache: npm }
- run: npm ci && npm run lint && npm testĐiểm đáng chú ý trong workflow trên:
- Matrix build: cùng một job được chạy trên nhiều phiên bản Node.js, giúp bạn biết code có tương thích hay không trước khi nâng cấp runtime.
- Cache dependency: tuỳ chọn
cache: npmcủasetup-nodelưu lại thư mục cache của npm dựa trênpackage-lock.json, giúp các lần chạy sau nhanh hơn. npm cithay vìnpm install:npm cicài đúng phiên bản trong lock file và báo lỗi nếu lock file không khớppackage.json, đảm bảo môi trường CI tái lập được.
Hãy kiểm tra tài liệu chính thức để dùng phiên bản action mới nhất, vì các action như checkout và setup-node được cập nhật định kỳ.
Bảo vệ nhánh chính
CI chỉ thực sự có giá trị khi kết quả của nó được tôn trọng. Trong phần cài đặt repository, hãy bật branch protection (hoặc ruleset) cho nhánh main, yêu cầu job test phải thành công trước khi merge pull request. Như vậy, không ai có thể vô tình merge code làm hỏng test.
Thêm bước triển khai (CD)
Sau khi job test thành công, ta có thể thêm job triển khai chỉ chạy khi có push lên main:
deploy:
needs: test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v6
- run: ./scripts/deploy.sh
env:
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}needs: testđảm bảo chỉ triển khai khi mọi phiên bản trong matrix đều qua test.environment: productioncho phép cấu hình quy tắc bảo vệ, ví dụ yêu cầu người duyệt trước khi job chạy, và gắn secrets riêng cho môi trường đó.secrets.DEPLOY_TOKENlấy giá trị bí mật đã lưu trong cài đặt repository hoặc environment. GitHub tự động che giá trị secrets trong log.
Nội dung deploy.sh tuỳ vào hạ tầng của bạn: build Docker image và đẩy lên registry, gọi API của nền tảng hosting, hoặc đồng bộ tệp lên server.
Thực hành tốt về bảo mật
- Không bao giờ ghi trực tiếp khoá bí mật trong tệp workflow. Luôn dùng secrets.
- Giới hạn quyền của
GITHUB_TOKENbằng khốipermissions, ví dụ chỉ cấpcontents: readcho job không cần ghi. - Ưu tiên OIDC khi triển khai lên cloud: nhiều nhà cung cấp như AWS, Azure, Google Cloud hỗ trợ xác thực bằng token ngắn hạn qua OpenID Connect, thay vì lưu khoá truy cập dài hạn.
- Cẩn trọng với action của bên thứ ba: đây là một phần chuỗi cung ứng phần mềm. Với action không phải của tổ chức tin cậy, cân nhắc ghim theo commit SHA đầy đủ thay vì tag.
- Cẩn thận với sự kiện
pull_request_target: nó chạy với quyền của repository gốc, nên không được checkout và thực thi code từ fork một cách tuỳ tiện.
Mẹo tối ưu pipeline
- Tách lint, test, build thành các job riêng nếu chúng tốn thời gian, để chạy song song và dễ xác định lỗi.
- Dùng
concurrencyđể huỷ các lần chạy cũ khi có commit mới trên cùng một nhánh, tiết kiệm phút chạy. - Lưu kết quả build hoặc báo cáo coverage bằng artifact để các job sau hoặc người review sử dụng.
- Giữ workflow ngắn gọn; khi có nhiều repository dùng chung logic, hãy cân nhắc reusable workflow.
Kết luận
Thiết lập CI/CD với GitHub Actions cho dự án Node.js chỉ mất chưa đến một giờ nhưng mang lại lợi ích lâu dài: lỗi được phát hiện sớm, quy trình triển khai nhất quán và đội ngũ tự tin hơn mỗi lần phát hành. Hãy bắt đầu từ một workflow CI đơn giản với lint và test, bật bảo vệ nhánh, rồi từng bước bổ sung triển khai tự động cùng các biện pháp bảo mật như secrets, giới hạn quyền và OIDC.






