Bỏ qua

Deployment Workflow

Tổng quan quy trình

┌─────────────────────────────────────────────────────────────┐
│                    DEPLOYMENT PIPELINE                       │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   Developer ──▶ Git Push ──▶ GitHub Actions ──▶ Cloudflare  │
│                                                              │
│   ┌──────────┐    ┌──────────┐    ┌──────────┐              │
│   │  Local   │───▶│  Build   │───▶│  Deploy  │              │
│   │   Dev    │    │  & Test  │    │  Worker  │              │
│   └──────────┘    └──────────┘    └──────────┘              │
│                                                              │
└─────────────────────────────────────────────────────────────┘

Manual Deployment

Deploy trực tiếp từ local

# 1. Build Next.js
npm run build

# 2. Build for Cloudflare
npm run build:worker

# 3. Deploy to production
wrangler deploy

# Output:
# Uploaded my-app (1.23 sec)
# Published my-app (0.45 sec)
#   https://my-app.username.workers.dev

Deploy với environment

# Deploy to staging
wrangler deploy --env staging

# Deploy to production
wrangler deploy --env production

Multi-environment Setup

wrangler.toml với environments

name = "my-nextjs-app"
main = ".open-next/worker.js"
compatibility_date = "2024-09-23"
compatibility_flags = ["nodejs_compat"]

[assets]
directory = ".open-next/assets"
binding = "ASSETS"

# ==================
# Development (default)
# ==================
[vars]
ENVIRONMENT = "development"
NEXT_PUBLIC_API_URL = "http://localhost:3000"

[[kv_namespaces]]
binding = "CACHE"
id = "dev-kv-id"

# ==================
# Staging
# ==================
[env.staging]
name = "my-app-staging"
routes = [{ pattern = "staging.myapp.com", custom_domain = true }]

[env.staging.vars]
ENVIRONMENT = "staging"
NEXT_PUBLIC_API_URL = "https://staging.myapp.com"

[[env.staging.kv_namespaces]]
binding = "CACHE"
id = "staging-kv-id"

# ==================
# Production
# ==================
[env.production]
name = "my-app-production"
routes = [{ pattern = "myapp.com", custom_domain = true }]

[env.production.vars]
ENVIRONMENT = "production"
NEXT_PUBLIC_API_URL = "https://myapp.com"

[[env.production.kv_namespaces]]
binding = "CACHE"
id = "production-kv-id"

Secrets Management

Set secrets via CLI

# Development (default)
wrangler secret put SUPABASE_SERVICE_KEY
# Enter value: sk_xxx

# Staging
wrangler secret put SUPABASE_SERVICE_KEY --env staging

# Production
wrangler secret put SUPABASE_SERVICE_KEY --env production

List secrets

wrangler secret list
wrangler secret list --env production

Delete secret

wrangler secret delete SECRET_NAME

GitHub Actions CI/CD

Workflow file

# .github/workflows/deploy.yml
name: Deploy to Cloudflare

on:
  push:
    branches:
      - main        # Production
      - staging     # Staging
  pull_request:
    branches:
      - main

env:
  NODE_VERSION: '20'

jobs:
  # ================
  # Build & Test
  # ================
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run linting
        run: npm run lint

      - name: Run tests
        run: npm run test

      - name: Build Next.js
        run: npm run build

      - name: Build for Cloudflare
        run: npm run build:worker

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-output
          path: .open-next/

  # ================
  # Deploy Staging
  # ================
  deploy-staging:
    needs: build
    if: github.ref == 'refs/heads/staging'
    runs-on: ubuntu-latest
    environment: staging

    steps:
      - uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: .open-next/

      - name: Deploy to Cloudflare (Staging)
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy --env staging

  # ================
  # Deploy Production
  # ================
  deploy-production:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production

    steps:
      - uses: actions/checkout@v4

      - name: Download build artifacts
        uses: actions/download-artifact@v4
        with:
          name: build-output
          path: .open-next/

      - name: Deploy to Cloudflare (Production)
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy --env production

GitHub Secrets Setup

Required secrets

Secret Description How to get
CLOUDFLARE_API_TOKEN API token với Workers permissions Cloudflare Dashboard → Profile → API Tokens
CLOUDFLARE_ACCOUNT_ID Account ID Cloudflare Dashboard → Workers → Account ID

Tạo API Token

1. Cloudflare Dashboard → Profile → API Tokens
2. Create Token
3. Use template: "Edit Cloudflare Workers"
4. Account Resources: Include → Your Account
5. Zone Resources: Include → All zones
6. Create Token
7. Copy token → Add to GitHub Secrets

Preview Deployments (Pull Requests)

Thêm preview deployment

# .github/workflows/preview.yml
name: Preview Deployment

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install & Build
        run: |
          npm ci
          npm run build
          npm run build:worker

      - name: Deploy Preview
        id: deploy
        uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy --env preview

      - name: Comment Preview URL
        uses: actions/github-script@v7
        with:
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: '🚀 Preview deployed: ${{ steps.deploy.outputs.deployment-url }}'
            })

Rollback Strategy

Quick rollback

# List recent deployments
wrangler deployments list --env production

# Rollback to previous version
wrangler rollback --env production

# Rollback to specific version
wrangler rollback <deployment-id> --env production

Via Dashboard

1. Cloudflare Dashboard → Workers
2. Select your worker
3. Deployments tab
4. Click "Rollback" on previous deployment

Deployment Best Practices

Checklist trước deploy

  • [ ] Tất cả tests pass
  • [ ] Environment variables đã set
  • [ ] Secrets đã set cho environment
  • [ ] Database migrations đã chạy
  • [ ] Build thành công locally

Monitoring sau deploy

# Watch logs
wrangler tail --env production

# Check metrics
# Cloudflare Dashboard → Workers → Analytics

Tổng kết

Deployment Flow

┌──────────┐     ┌──────────┐     ┌──────────┐
│   Dev    │────▶│ Staging  │────▶│Production│
│  Branch  │     │  Branch  │     │  Branch  │
└──────────┘     └──────────┘     └──────────┘
     │                │                │
     ▼                ▼                ▼
┌──────────┐     ┌──────────┐     ┌──────────┐
│  Preview │     │ Staging  │     │Production│
│   URL    │     │   URL    │     │   URL    │
└──────────┘     └──────────┘     └──────────┘

Key Commands

# Local preview
npm run preview

# Deploy to staging
wrangler deploy --env staging

# Deploy to production
wrangler deploy --env production

# Rollback
wrangler rollback --env production

# View logs
wrangler tail --env production

Q&A

  1. Team bạn đang dùng CI/CD tool nào?
  2. Có cần preview deployments không?
  3. Rollback strategy hiện tại là gì?