CI/CD Pipeline — Tự Động Hóa Từ Commit Đến Production
Xây dựng CI/CD pipeline với GitHub Actions: lint, test, build, deploy tự động mỗi lần push code.
CI/CD (Continuous Integration / Continuous Deployment) là xương sống của quy trình phát triển hiện đại. Mỗi lần push code — tự động kiểm tra, build, và deploy.
CI vs CD#
| CI (Continuous Integration) | CD (Continuous Deployment/Delivery) |
|---|---|
| Lint, test, build khi push | Deploy lên staging/production |
| Đảm bảo code mới không hỏng | Đảm bảo luôn sẵn sàng release |
| Chạy trên mỗi PR | Chạy khi merge vào main |
GitHub Actions — Cấu Trúc Cơ Bản#
name: CI/CD Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run lint
- run: npm run test
- run: npm run buildyamlPipeline Hoàn Chỉnh#
1. Lint & Type Check#
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm run typecheckyaml2. Unit Test + Coverage#
test:
needs: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run test:cov
- uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/yaml3. Build & Push Docker Image#
build:
needs: test
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to registry
run: |
docker tag myapp:${{ github.sha }} registry.example.com/myapp:${{ github.sha }}
docker push registry.example.com/myapp:${{ github.sha }}yaml4. Deploy#
deploy:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- name: Deploy to server
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SSH_KEY }}
script: |
docker pull registry.example.com/myapp:${{ github.sha }}
docker stop myapp || true
docker rm myapp || true
docker run -d --name myapp -p 3000:3000 \
-e DATABASE_URL=${{ secrets.DATABASE_URL }} \
registry.example.com/myapp:${{ github.sha }}yamlMatrix Build — Test Nhiều Phiên Bản#
test:
strategy:
matrix:
node-version: [18, 20, 22]
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm testyamlCaching — Tăng Tốc Pipeline#
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-yamlSecrets — Không Hardcode#
Trong GitHub:
Settings > Secrets and variables > ActionsplaintextThêm: SERVER_HOST, DB_PASSWORD, API_KEY, SSH_KEY…
Dùng trong workflow:
- run: echo "${{ secrets.SSH_KEY }}" > ssh_keyyamlDocker Compose Cho Test Integration#
test-integration:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_PASSWORD: testpass
options: >-
--health-cmd pg_isready
--health-interval 10s
redis:
image: redis:7-alpine
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:integration
env:
DATABASE_URL: postgres://postgres:testpass@localhost:5432/postgres
REDIS_URL: redis://localhost:6379yamlAuto Deploy — Vercel / Cloudflare Pages#
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci && npm run build
- name: Deploy to Cloudflare Pages
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CF_API_TOKEN }}
command: pages deploy dist/yamlGitOps — Deploy Bằng Git#
Không ssh vào server — push config vào git repo, tool tự đồng bộ:
# ArgoCD + Kubernetes
# Push image tag mới vào Git repo config → ArgoCD tự deployyamlBadges — Cho README#
[](https://github.com/user/repo/actions)markdownChecklist Pipeline#
- Lint & type check
- Unit test + coverage
- Integration test (DB, cache)
- Build Docker image
- Push registry
- Deploy staging
- Smoke test
- Deploy production
- Rollback plan
Kết Luận#
CI/CD không phải công cụ — nó là văn hóa. Code push lên là code đã được kiểm tra, đóng gói, sẵn sàng deploy. Mất 1 ngày setup, tiết kiệm hàng trăm giờ debug “tại sao chạy được ở máy tôi?”.