Bấm git push. Tab Actions quay tít thò lòi mười hai phút. Cuối tháng nhận email cảnh báo hết phút Runner miễn phí.
Đó là kịch bản quen thuộc khi lập trình viên bê nguyên file YAML mẫu trên mạng vào dự án thực tế. Hầu hết pipeline hiện nay mắc hai sai lầm nghiêm trọng: lãng phí thời gian build vì cache chưa đúng cách, và chôn rủi ro bảo mật lớn khi dán AWS Access Key dài hạn vào GitHub Secrets.
Bài viết này tối ưu lại pipeline GitHub Actions theo chuẩn sản xuất: chạy nhanh hơn đáng kể, giảm thiểu rủi ro bảo mật với OIDC, và có quy trình kiểm thử pipeline ngay tại máy cá nhân trước khi push.
1. Hai “Điểm Nghẽn” Khiến Pipeline Vừa Chậm Vừa Rủi Ro
❌ Điểm nghẽn 1: Cài lại dependencies từ đầu ở mỗi commit
Mỗi lần job chạy, GitHub khởi tạo một máy ảo Ubuntu mới tinh. Nếu không cấu hình cache đúng cách, lệnh npm ci hay pip install sẽ phải tải lại hàng trăm MB thư viện qua mạng trong khi kết quả lần build trước vẫn còn nguyên — chỉ vì runner không biết cách tận dụng.
❌ Điểm nghẽn 2: Dùng AWS Access Key dài hạn
Lưu AWS_ACCESS_KEY_ID và AWS_SECRET_ACCESS_KEY trong GitHub Secrets là cách làm cũ. Nếu tài khoản GitHub hoặc repo bị can thiệp, cặp key này có thể bị lộ, và kẻ xấu sẽ dùng nó để đào coin trên tài khoản AWS của bạn. Long-lived key cũng khó kiểm soát vì không có thời điểm hết hạn rõ ràng — nó sống cho đến khi bạn nhớ thu hồi.
2. Giải Pháp Sản Xuất: OIDC + Caching Đúng Chuẩn
Thay vì dùng key dài hạn, chuẩn bảo mật hiện nay là OpenID Connect (OIDC). GitHub Actions sẽ tự thỏa thuận với AWS (hoặc GCP, Azure) để xin một token ngắn hạn — chỉ sống trong vài phút — để thực hiện deploy, sau đó token tự hủy. Không có bí mật nào nằm yên trong Secrets để chờ bị lộ.
Dưới đây là file workflow YAML chuẩn sản xuất, tích hợp đầy đủ: OIDC, phân quyền tối thiểu (least privilege), và caching tự động qua cache key của chính GitHub Actions:
name: Production CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
# BẮT BUỘC: Chỉ cấp quyền đọc code và xin ID Token cho OIDC.
# Không để mặc định — default permission của GITHUB_TOKEN đã có writeContents.
permissions:
id-token: write # Cần thiết để xác thực OIDC với AWS/GCP
contents: read # Chỉ đọc source code, không cấp quyền ghi
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
# Step 1: Checkout mã nguồn
- name: Checkout Code
uses: actions/checkout@v4
# Step 2: Setup Node.js kèm caching tự động theo package-lock.json
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # Cache npm package cache dựa trên package-lock.json
# Step 3: Cài dependencies (cực nhanh khi hit cache).
# npm ci đọc cache nội bộ mà setup-node vừa restore.
- name: Install Dependencies
run: npm ci
# Step 4: Chạy kiểm thử
- name: Run Tests
run: npm test
deploy-aws:
needs: build-and-test
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
# Step 5: Xác thực AWS bằng OIDC — không cần lưu Access Key dài hạn.
# Role ARN phải tồn tại trong IAM với trust policy cho phép
# token.actions.githubusercontent.com từ repo này.
- name: Configure AWS Credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/GitHubActionsDeployRole
aws-region: ap-southeast-1
# Step 6: Thực thi deploy. Token do OIDC cấp chỉ sống vài phút,
# ngay sau khi job kết thúc sẽ tự hết hiệu lực.
- name: Deploy to Production
run: |
echo "Xác thực OIDC thành công! Đang triển khai ứng dụng..."
# aws s3 sync ./build s3://your-bucket --delete
# aws ecs update-service --cluster prod --service web --force-new-deployment
Lưu ý kỹ thuật quan trọng: cache: 'npm' không trực tiếp cache node_modules. Nó cache npm package cache (~/.npm) và chỉ dùng lại được khi package-lock.json không đổi. npm ci sau đó sẽ đọc từ cache này để bỏ qua bước tải về. Nếu bạn đổi một dòng trong package-lock.json, cache key thay đổi và một cache mới sẽ được tạo — đây là hành vi đúng, vì nội dung thư viện giờ khác.
3. Mẹo Debug Workflow Ngay Tại Local
Mỗi lần sửa file YAML lại phải git commit và git push để xem nó chạy đúng hay sai là một trải nghiệm rất tệ.
Hãy dùng công cụ mã nguồn mở act để giả lập và chạy thử GitHub Actions ngay trên máy của bạn thông qua Docker:
# macOS / Linux
brew install act
# Windows (Chocolatey)
choco install act-cli
# Chạy thử job 'build-and-test' ngay tại terminal
act -j build-and-test
act sẽ đọc file trong thư mục .github/workflows/ và kéo container Ubuntu về máy để chạy thử. Bạn sẽ biết ngay file YAML bị lỗi cú pháp ở dòng nào mà không làm bẩn lịch sử commit.
Hai lưu ý thực tế khi dùng act:
- Secrets và OIDC không tự động có sẵn. Bạn cần truyền thủ công qua
act --secret AWS_ROLE_TO_ASSUME=...hoặc file.env— không phải cứ đẩy lên GitHub là chạy được phần OIDC. - Container runner hơi khác GitHub-hosted. Một số edge case (ví dụ service container, matrix phức tạp) có thể chạy khác trên GitHub Actions thật. Hãy coi
actlà bộ lọc lỗi cú pháp sớm, không phải môi trường test đầy đủ.
4. Bảng Kiểm Tra (Checklist) Cho Một Pipeline Chuẩn Sản Xuất
- Cache qua action chính thức — dùng
cache: 'npm'trongactions/setup-node, hoặcactions/cachevới key dựa trên hash file lock tương ứng (package-lock.json,requirements.txt,go.sum). - Hạ quyền token mặc định — khai báo khối
permissions:ở đầu file YAML theo nguyên tắc least privilege, không để GITHUB_TOKEN ngầm cówrite. - Chuyển sang OIDC — loại bỏ long-lived access key khỏi Secrets; thiết lập IAM role với trust policy cho
token.actions.githubusercontent.com. - Test local bằng
act— đảm bảo YAML không sai thụt lề hoặc sai tham chiếu step trước khi push. - Tách job build và deploy — dùng
needs:+ điều kiệnif: github.ref == 'refs/heads/main'để deploy chỉ chạy sau khi test pass trên main.
Nguồn tham khảo: