GitHub Actions — Pipeline CI/CD tự động cho dự án thật sự

Phong Hy

GitHub Actions — Pipeline CI/CD tự động cho dự án thật sự

Xưa mình cứ nghĩ deploy là việc "gõ lệnh ssh rồi copy code". Lên dự án thật sự, nhiều lần tay mồm hơn tay code: quên test, deploy nhầm nhánh, cache X chỗ không đâu. Cho tới khi chuyển hết sang GitHub Actions, mọi thứ thành một luồng tự động, ai push nhánh main là tự nó test + build + deploy, mình chỉ ngồi xem kết quả. Bài này mình ghi lại những thứ làm dự án CI/CD chạy ngon và đúng.

1. Workflow cơ bản — YAML là vua

Một workflow là file .github/workflows/deploy.yml. Phần quan trọng nhất là triggers (on) và jobs:

name: CI/CD

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: '1.22'
      - run: go test ./...

Chú ý là checkout@v4, setup-go@v5chỉ định version sha hoặc major, đừng dùng @main trên action bên ngoài, kẻo một hôm nó đổi behaviour là build chết bất ngờ.

2. Matrix build — chạy song song nhiều version

Muốn chắc app chạy trên nhiều version Go, Node... thì dùng strategy.matrix. GitHub tự đẻ ra N job song song từ một định nghĩa:

strategy:
  matrix:
    go: ['1.21', '1.22', '1.23']
steps:
  - uses: actions/setup-go@v5
    with:
      go-version: ${{ matrix.go }}

Chạy song song nghĩa là nhanh hơn, nhưng để ý free tier chỉ có 20 job đồng thời/account — project nhiều matrix quá mức là bị xếp hàng chặt.

3. Cache dependency — đừng để mỗi lần tải lại từ đầu

Dependency chậm nhất chỗ nào? Tải go mod hay npm install mỗi lần từ zero. Dùng action cache:

- uses: actions/cache@v4
  with:
    path: ~/.cache/go-build
    key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}

hashFiles là chìa khoá: cache chỉ hợp lệ khi go.sum không đổi. Nhờ vậy giảm thời gian pipeline từ 5 phút xuống còn 40 giây — kinh nghiệm thật, không phải lý thuyết.

4. Secrets — đừng bao giờ hardcode

Cấu hình quan trọng nhất: không ghi credential thẳng vào YAML. Qua tab Settings → Secrets → Actions mà khai báo, rồi dùng ${{ secrets.X }}:

- name: Deploy
  env:
    SUPABASE_URL: ${{ secrets.SUPABASE_URL }}
    SERVICE_KEY: ${{ secrets.SERVICE_ROLE_KEY }}
  run: |
    curl -X POST "$SUPABASE_URL/rest/v1/posts" \
      -H "Authorization: Bearer $SERVICE_KEY" ...

GitHub tự mask value của secret trong log — không sợ lộ ra terminal. Nhớ để quyền tối thiểu: cho service role vào build là giết con gà lấy trứng.

5. Deploy tự động — production an toàn

Cuối cùng là nhánh deploy. Quy tắc mình áp dụng:

  • Test xong mới build — job test là dependency của job deploy
  • Build image xong push lên registry rồi mới update container
  • Không deploy khi test fail — GitHub tự chặn vì job deploy needs: test
deploy:
  needs: test
  runs-on: ubuntu-latest
  steps:
    - run: ./deploy.sh  # đọc env từ secrets

Kinh nghiệm dính đòn

  1. Checkout thiếu — action đầu tiên luôn phải actions/checkout, không có thì chạy như mù.
  2. Version action lỏng — dùng @v4 not @main.
  3. Secrets vào log — logs là nơi dễ lộ nhất, test cẩn thận trước khi chạy thật.
  4. Cache key sai — cache vô dụng khi hash không khớp file dependencies.

CI/CD không phải phép màu, nó chỉ là kỷ luật đóng khung. Có pipeline tự động, mỗi lần push là mình biết liền code có vỡ không — không còn "nó chạy trên máy tui mà". Nếu project bạn còn đang dùng cách deploy tay, bắt đầu từ workflow 5 dòng test này là đủ thay đổi cuộc chơi. 🚀