Bỏ qua đến nội dung chính
CI/CDGitHub ActionsDevOpsautomationNode.js

CI/CD Pipeline Với GitHub Actions Cho Node.js

CI/CD pipeline GitHub Actions cho Node.js: lint, test, build Docker, deploy. Workflow YAML production-ready, cache, secret, environment.

Xuất bản 8 phút đọc

CI/CD pipeline tốt là khoản đầu tư có ROI cao nhất cho team backend. Mỗi PR được test tự động, deploy 1-click, rollback dễ. Bài này đi qua workflow GitHub Actions production-ready cho Node.js, từ lint đến deploy K8s.

CI vs CD

  • CI (Continuous Integration): mỗi commit tự động lint + test + build. Catch bug sớm.
  • CD (Continuous Delivery/Deployment): build artifact tự deploy đến staging (delivery) hoặc production (deployment).

CI workflow đầy đủ

# .github/workflows/ci.yml
name: CI

on:
  pull_request:
  push: { branches: [main] }

concurrency:
  group: ci-${{ github.ref }}
  cancel-in-progress: true

jobs:
  lint-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        node: [22, 24]
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-node@v4
        with:
          node-version: ${{ matrix.node }}
          cache: 'npm'                # auto-cache theo package-lock.json hash

      - run: npm ci

      - run: npm run lint
      - run: npm run typecheck
      - run: npm test -- --coverage

      - uses: codecov/codecov-action@v4
        if: matrix.node == '22'
        with: { files: ./coverage/coverage-final.json }

  e2e:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:16
        env: { POSTGRES_PASSWORD: test }
        ports: ['5432:5432']
        options: --health-cmd pg_isready --health-interval 5s
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22, cache: 'npm' }
      - run: npm ci
      - run: npm run db:migrate
        env: { DATABASE_URL: postgres://postgres:test@localhost/postgres }
      - run: npm run test:e2e
        env: { DATABASE_URL: postgres://postgres:test@localhost/postgres }

concurrency cancel CI run cũ khi push commit mới — tiết kiệm minute.

Build Docker image với cache

  build-image:
    needs: [lint-test, e2e]
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    permissions:
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - uses: docker/setup-buildx-action@v3

      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - uses: docker/metadata-action@v5
        id: meta
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=sha,prefix=
            type=raw,value=latest,enable={{is_default_branch}}

      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max
          platforms: linux/amd64,linux/arm64

BuildKit + GitHub Actions cache giảm rebuild từ 5 phút còn 30 giây cho thay đổi nhỏ.

CD đến staging (auto)

  deploy-staging:
    needs: build-image
    runs-on: ubuntu-latest
    environment:
      name: staging
      url: https://staging.alodev.vn
    permissions:
      id-token: write    # OIDC
      contents: read
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ vars.AWS_DEPLOY_ROLE }}
          aws-region: ap-southeast-1

      - run: |
          aws eks update-kubeconfig --name alodev-staging
          kubectl set image deployment/alodev-api app=ghcr.io/${{ github.repository }}:${{ github.sha }}
          kubectl rollout status deployment/alodev-api --timeout=2m

OIDC: aws-actions/configure-aws-credentials mint token short-lived. Không có AWS_ACCESS_KEY trong secret.

CD production (require approval)

  deploy-production:
    needs: deploy-staging
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://alodev.vn
    # Environment 'production' đã setup require_review trong UI:
    # Settings → Environments → production → Required reviewers
    steps:
      - uses: aws-actions/configure-aws-credentials@v4
        with: { role-to-assume: ${{ vars.AWS_PROD_DEPLOY_ROLE }} }

      - name: Database migration
        run: ./scripts/migrate-prod.sh

      - name: Deploy
        run: |
          kubectl set image deployment/alodev-api app=ghcr.io/${{ github.repository }}:${{ github.sha }} -n production
          kubectl rollout status deployment/alodev-api -n production

      - name: Smoke test
        run: curl -f https://alodev.vn/healthz

Reviewer click "Approve" trong PR run page mới deploy. Có thể setup branch protection: chỉ main mới deploy được prod.

Reusable workflow

Logic deploy giống nhau giữa staging/prod → tách reusable:

# .github/workflows/deploy.yml
on:
  workflow_call:
    inputs:
      environment: { required: true, type: string }
      cluster:     { required: true, type: string }
    secrets:
      AWS_ROLE: { required: true }

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: ${{ inputs.environment }}
    steps:
      # ... shared deploy logic
# Caller workflow:
deploy-staging:
  uses: ./.github/workflows/deploy.yml
  with:
    environment: staging
    cluster: alodev-staging
  secrets:
    AWS_ROLE: ${{ secrets.STAGING_AWS_ROLE }}

Best practices

  • Fail fast: lint + typecheck trước test (phát hiện bug 5s vs 5 phút)
  • Cache deps theo lockfile, Docker build theo gha cache
  • Concurrency cancel in-progress khi push commit mới
  • OIDC thay static secret cho cloud auth
  • Environment + required review cho production
  • Smoke test sau deploy — fail thì rollback tự động
  • Notification Slack khi deploy success/fail

Kết luận

CI/CD pipeline tốt là tự động hoá tin cậy: PR review xong, click merge, 5 phút sau code đã chạy production. Bắt đầu đơn giản với CI lint + test, thêm CD khi confident. GitHub Actions là lựa chọn default cho repo trên GitHub. Tham khảo Database migration safe để deploy schema change không downtime, và Blue-green deployment cho zero-risk rollback.

Zalo