deployment

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Resources

资源

scripts/
  validate-deployment.sh
references/
  deployment-platforms.md
scripts/
  validate-deployment.sh
references/
  deployment-platforms.md

Deployment

部署

This skill guides you through deploying applications to production using modern platforms and tools. Use this workflow when deploying Next.js, full-stack apps, containerized services, or serverless functions.
本技能将指导你使用现代平台和工具将应用部署到生产环境。当部署Next.js、全栈应用、容器化服务或无服务器函数时,可使用此工作流。

When to Use This Skill

何时使用本技能

  • Deploying applications to Vercel, Railway, Fly.io, or AWS
  • Setting up CI/CD pipelines with GitHub Actions
  • Configuring Docker containers for production
  • Implementing health checks and monitoring
  • Creating preview deployments for pull requests
  • Setting up rollback and canary deployment strategies
  • 将应用部署到Vercel、Railway、Fly.io或AWS
  • 使用GitHub Actions设置CI/CD流水线
  • 配置生产环境的Docker容器
  • 实现健康检查与监控
  • 为拉取请求创建预览部署
  • 设置回滚与金丝雀部署策略

Platform Selection

平台选择

Choose the right platform based on your application needs:
根据应用需求选择合适的平台:

Vercel (Best for Next.js)

Vercel(最适合Next.js)

When to use:
  • Next.js applications (App Router or Pages Router)
  • Static sites with edge functions
  • Automatic preview deployments per PR
  • Zero-config deployments
Setup:
bash
undefined
适用场景:
  • Next.js应用(App Router或Pages Router)
  • 带边缘函数的静态站点
  • 每个PR自动生成预览部署
  • 零配置部署
设置步骤:
bash
undefined

Install Vercel CLI

安装Vercel CLI

npm install -g vercel
npm install -g vercel

Deploy

部署

vercel --prod

**Environment variables:**
```bash
vercel --prod

**环境变量:**
```bash

Set production secrets

设置生产环境密钥

vercel env add DATABASE_URL production vercel env add NEXTAUTH_SECRET production
undefined
vercel env add DATABASE_URL production vercel env add NEXTAUTH_SECRET production
undefined

Railway (Best for Full-Stack)

Railway(最适合全栈应用)

When to use:
  • Full-stack apps with databases
  • Monorepo deployments
  • PostgreSQL, Redis, MongoDB hosting
  • WebSocket support
Setup:
bash
undefined
适用场景:
  • 带数据库的全栈应用
  • 单仓库部署
  • PostgreSQL、Redis、MongoDB托管
  • WebSocket支持
设置步骤:
bash
undefined

Install Railway CLI

安装Railway CLI

npm install -g @railway/cli
npm install -g @railway/cli

Login and deploy

登录并部署

railway login railway up

**railway.json:**
```json
{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "npm run build"
  },
  "deploy": {
    "startCommand": "npm start",
    "healthcheckPath": "/api/health",
    "healthcheckTimeout": 100,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 3
  }
}
railway login railway up

**railway.json:**
```json
{
  "$schema": "https://railway.app/railway.schema.json",
  "build": {
    "builder": "NIXPACKS",
    "buildCommand": "npm run build"
  },
  "deploy": {
    "startCommand": "npm start",
    "healthcheckPath": "/api/health",
    "healthcheckTimeout": 100,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 3
  }
}

Fly.io (Best for Containers)

Fly.io(最适合容器)

When to use:
  • Custom container requirements
  • Global edge deployment
  • Long-running processes
  • Fine-grained scaling control
Setup:
bash
undefined
适用场景:
  • 自定义容器需求
  • 全球边缘部署
  • 长期运行的进程
  • 细粒度的扩缩容控制
设置步骤:
bash
undefined

Install Fly CLI

安装Fly CLI

Initialize and deploy

初始化并部署

fly launch fly deploy

**fly.toml:**
```toml
app = "my-app"
primary_region = "sjc"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0

[[http_service.checks]]
  grace_period = "10s"
  interval = "30s"
  method = "GET"
  timeout = "5s"
  path = "/api/health"

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 256
fly launch fly deploy

**fly.toml:**
```toml
app = "my-app"
primary_region = "sjc"

[build]
  dockerfile = "Dockerfile"

[env]
  PORT = "8080"

[http_service]
  internal_port = 8080
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 0

[[http_service.checks]]
  grace_period = "10s"
  interval = "30s"
  method = "GET"
  timeout = "5s"
  path = "/api/health"

[[vm]]
  cpu_kind = "shared"
  cpus = 1
  memory_mb = 256

Docker (Best for Self-Hosted)

Docker(最适合自托管)

When to use:
  • Self-hosted infrastructure
  • VPS deployments (DigitalOcean, Linode)
  • Local development parity
  • Multi-service orchestration
See references/deployment-platforms.md for Dockerfile examples.
适用场景:
  • 自托管基础设施
  • VPS部署(DigitalOcean、Linode)
  • 本地开发与生产环境一致
  • 多服务编排
Dockerfile示例请查看references/deployment-platforms.md。

AWS (Best for Enterprise)

AWS(最适合企业级)

When to use:
  • Enterprise requirements
  • Compliance/regulatory needs
  • Complex infrastructure
  • Multi-region deployments
Services:
  • ECS Fargate: Serverless containers
  • Lambda: Serverless functions
  • Amplify: Full-stack deployments
  • Elastic Beanstalk: Managed platform
适用场景:
  • 企业级需求
  • 合规/监管要求
  • 复杂基础设施
  • 多区域部署
相关服务:
  • ECS Fargate:无服务器容器
  • Lambda:无服务器函数
  • Amplify:全栈部署
  • Elastic Beanstalk:托管平台

Environment Configuration

环境配置

.env Management

.env管理

Never commit secrets to git. Always use .env.example for documentation:
.env.example:
bash
undefined
切勿将密钥提交到git。始终使用.env.example作为文档:
.env.example:
bash
undefined

Database

数据库

DATABASE_URL="postgresql://user:password@localhost:5432/mydb"
DATABASE_URL="postgresql://user:password@localhost:5432/mydb"

Authentication

身份验证

NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="generate-with-openssl-rand-base64-32"
NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="generate-with-openssl-rand-base64-32"

External APIs

外部API

STRIPE_SECRET_KEY="sk_test_..." STRIPE_WEBHOOK_SECRET="whsec_..."
STRIPE_SECRET_KEY="sk_test_..." STRIPE_WEBHOOK_SECRET="whsec_..."

Feature Flags

功能开关

NEXT_PUBLIC_ENABLE_ANALYTICS="false"
undefined
NEXT_PUBLIC_ENABLE_ANALYTICS="false"
undefined

Environment Variable Validation

环境变量验证

Validate environment variables at build time to fail fast:
src/env.mjs:
javascript
import { z } from 'zod';

const server = z.object({
  DATABASE_URL: z.string().url(),
  NEXTAUTH_SECRET: z.string().min(32),
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});

const client = z.object({
  NEXT_PUBLIC_APP_URL: z.string().url(),
});

const processEnv = {
  DATABASE_URL: process.env.DATABASE_URL,
  NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
  STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
  NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
};

const merged = server.merge(client);
const parsed = merged.safeParse(processEnv);

if (!parsed.success) {
  console.error('[FAIL] Invalid environment variables:', parsed.error.flatten().fieldErrors);
  throw new Error('Invalid environment variables');
}

export const env = parsed.data;
Import at the top of your app to validate on startup:
typescript
import { env } from './env.mjs';

// Use typed, validated env
const db = new PrismaClient({
  datasources: { db: { url: env.DATABASE_URL } },
});
在构建时验证环境变量,提前发现错误:
src/env.mjs:
javascript
import { z } from 'zod';

const server = z.object({
  DATABASE_URL: z.string().url(),
  NEXTAUTH_SECRET: z.string().min(32),
  STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
});

const client = z.object({
  NEXT_PUBLIC_APP_URL: z.string().url(),
});

const processEnv = {
  DATABASE_URL: process.env.DATABASE_URL,
  NEXTAUTH_SECRET: process.env.NEXTAUTH_SECRET,
  STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
  NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
};

const merged = server.merge(client);
const parsed = merged.safeParse(processEnv);

if (!parsed.success) {
  console.error('[FAIL] Invalid environment variables:', parsed.error.flatten().fieldErrors);
  throw new Error('Invalid environment variables');
}

export const env = parsed.data;
在应用顶部导入以在启动时验证:
typescript
import { env } from './env.mjs';

// 使用经过类型验证的环境变量
const db = new PrismaClient({
  datasources: { db: { url: env.DATABASE_URL } },
});

CI/CD Pipelines

CI/CD流水线

GitHub Actions Workflow

GitHub Actions工作流

Create
.github/workflows/deploy.yml
:
yaml
name: Deploy

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

env:
  NODE_VERSION: '20'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          SKIP_ENV_VALIDATION: true

  deploy:
    runs-on: ubuntu-latest
    needs: [build]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'
创建
.github/workflows/deploy.yml
yaml
name: Deploy

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

env:
  NODE_VERSION: '20'

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Lint
        run: npm run lint

  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Run tests
        run: npm test

  build:
    runs-on: ubuntu-latest
    needs: [lint, test]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: Build
        run: npm run build
        env:
          SKIP_ENV_VALIDATION: true

  deploy:
    runs-on: ubuntu-latest
    needs: [build]
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Vercel
        uses: amondnet/vercel-action@v25
        with:
          vercel-token: ${{ secrets.VERCEL_TOKEN }}
          vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
          vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
          vercel-args: '--prod'

Caching Strategies

缓存策略

Speed up CI/CD with proper caching:
yaml
- name: Cache dependencies
  uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
    restore-keys: |
      ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
      ${{ runner.os }}-nextjs-
通过合理缓存加速CI/CD:
yaml
- name: Cache dependencies
  uses: actions/cache@v4
  with:
    path: |
      ~/.npm
      .next/cache
    key: ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
    restore-keys: |
      ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
      ${{ runner.os }}-nextjs-

Docker Production Setup

Docker生产环境设置

Multi-Stage Dockerfile

多阶段Dockerfile

Create an optimized production Dockerfile:
Dockerfile (Next.js):
dockerfile
FROM node:20-alpine AS base
创建优化的生产环境Dockerfile:
Dockerfile(Next.js):
dockerfile
FROM node:20-alpine AS base

Install dependencies only when needed

仅在需要时安装依赖

FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app
COPY package.json package-lock.json ./ RUN npm ci
FROM base AS deps RUN apk add --no-cache libc6-compat WORKDIR /app
COPY package.json package-lock.json ./ RUN npm ci

Rebuild the source code only when needed

仅在需要时重新构建源代码

FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build

Production image, copy all the files and run next

生产环境镜像,复制所有文件并运行next

FROM base AS runner WORKDIR /app
ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public
FROM base AS runner WORKDIR /app
ENV NODE_ENV=production ENV NEXT_TELEMETRY_DISABLED=1
RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs
COPY --from=builder /app/public ./public

Set the correct permission for prerender cache

为预渲染缓存设置正确权限

RUN mkdir .next RUN chown nextjs:nodejs .next
RUN mkdir .next RUN chown nextjs:nodejs .next

Automatically leverage output traces to reduce image size

自动利用输出跟踪减小镜像体积

COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000 ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

**next.config.js:**
```javascript
module.exports = {
  output: 'standalone', // Required for Docker
};
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000 ENV HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]

**next.config.js:**
```javascript
module.exports = {
  output: 'standalone', // Docker部署必需
};

.dockerignore

.dockerignore

Exclude unnecessary files from the Docker build:
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
.gitignore
.env*.local
.vscode
.idea
dist
build
coverage
*.md
!README.md
排除Docker构建中不需要的文件:
Dockerfile
.dockerignore
node_modules
npm-debug.log
README.md
.next
.git
.gitignore
.env*.local
.vscode
.idea
dist
build
coverage
*.md
!README.md

Build and Run

构建与运行

bash
undefined
bash
undefined

Build the image

构建镜像

docker build -t my-app .
docker build -t my-app .

Run with environment variables

带环境变量运行

docker run -p 3000:3000
-e DATABASE_URL="postgresql://..."
-e NEXTAUTH_SECRET="..."
my-app
undefined
docker run -p 3000:3000
-e DATABASE_URL="postgresql://..."
-e NEXTAUTH_SECRET="..."
my-app
undefined

Health Checks

健康检查

Health Check Endpoint

健康检查端点

Create a health check endpoint for monitoring:
app/api/health/route.ts:
typescript
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';

export async function GET() {
  try {
    // Check database connection
    await prisma.$queryRaw`SELECT 1`;
    
    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      database: 'connected',
    });
  } catch (error) {
    return NextResponse.json(
      {
        status: 'unhealthy',
        timestamp: new Date().toISOString(),
        database: 'disconnected',
        error: error instanceof Error ? error.message : 'Unknown error',
      },
      { status: 503 }
    );
  }
}
创建用于监控的健康检查端点:
app/api/health/route.ts:
typescript
import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';

export async function GET() {
  try {
    // 检查数据库连接
    await prisma.$queryRaw`SELECT 1`;
    
    return NextResponse.json({
      status: 'healthy',
      timestamp: new Date().toISOString(),
      uptime: process.uptime(),
      database: 'connected',
    });
  } catch (error) {
    return NextResponse.json(
      {
        status: 'unhealthy',
        timestamp: new Date().toISOString(),
        database: 'disconnected',
        error: error instanceof Error ? error.message : 'Unknown error',
      },
      { status: 503 }
    );
  }
}

Docker Health Check

Docker健康检查

Add health check to Dockerfile:
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"
在Dockerfile中添加健康检查:
dockerfile
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"

Kubernetes Liveness/Readiness

Kubernetes存活/就绪探针

yaml
livenessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 15
  periodSeconds: 20

readinessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10
yaml
livenessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 15
  periodSeconds: 20

readinessProbe:
  httpGet:
    path: /api/health
    port: 3000
  initialDelaySeconds: 5
  periodSeconds: 10

Preview Deployments

预览部署

Automatic PR Previews

PR自动预览

Vercel and Railway automatically create preview deployments for pull requests.
GitHub Actions for Railway:
yaml
on:
  pull_request:
    branches: [main]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Railway (PR)
        uses: bervProject/railway-deploy@main
        with:
          railway_token: ${{ secrets.RAILWAY_TOKEN }}
          service: ${{ secrets.RAILWAY_SERVICE }}
Vercel和Railway会自动为拉取请求创建预览部署。
Railway的GitHub Actions配置:
yaml
on:
  pull_request:
    branches: [main]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Deploy to Railway (PR)
        uses: bervProject/railway-deploy@main
        with:
          railway_token: ${{ secrets.RAILWAY_TOKEN }}
          service: ${{ secrets.RAILWAY_SERVICE }}

Comment on PR with Preview URL

在PR中评论预览URL

yaml
- name: Comment PR
  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: '[DEPLOY] Preview deployed to: https://pr-${{ github.event.number }}.myapp.com'
      })
yaml
- name: Comment PR
  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: '[DEPLOY] Preview deployed to: https://pr-${{ github.event.number }}.myapp.com'
      })

Rollback Strategies

回滚策略

Instant Rollback (Vercel)

即时回滚(Vercel)

bash
undefined
bash
undefined

List deployments

列出所有部署

vercel ls
vercel ls

Promote a previous deployment to production

将之前的部署升级为生产环境

vercel promote <deployment-url>
undefined
vercel promote <deployment-url>
undefined

Blue-Green Deployment

蓝绿部署

Deploy new version alongside old, then switch traffic:
bash
undefined
在旧版本旁部署新版本,然后切换流量:
bash
undefined

Deploy new version (green)

部署新版本(绿色环境)

fly deploy --strategy bluegreen
fly deploy --strategy bluegreen

Traffic switches automatically after health checks pass

健康检查通过后自动切换流量

Rollback if needed:

需要时回滚:

fly releases rollback
undefined
fly releases rollback
undefined

Canary Deployment

金丝雀部署

Gradually shift traffic to new version:
Fly.io canary:
bash
undefined
逐步将流量切换到新版本:
Fly.io金丝雀部署:
bash
undefined

Deploy canary (10% traffic)

部署金丝雀版本(10%流量)

fly deploy --strategy canary
fly deploy --strategy canary

Promote to 100% if successful

验证成功后升级为100%流量

fly releases promote
undefined
fly releases promote
undefined

Monitoring and Error Tracking

监控与错误追踪

Sentry Integration

Sentry集成

bash
npm install @sentry/nextjs
sentry.client.config.ts:
typescript
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
  enabled: process.env.NODE_ENV === 'production',
});
sentry.server.config.ts:
typescript
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
});
bash
npm install @sentry/nextjs
sentry.client.config.ts:
typescript
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
  enabled: process.env.NODE_ENV === 'production',
});
sentry.server.config.ts:
typescript
import * as Sentry from '@sentry/nextjs';

Sentry.init({
  dsn: process.env.SENTRY_DSN,
  tracesSampleRate: 1.0,
  environment: process.env.NODE_ENV,
});

Uptime Monitoring

可用性监控

Use external services to monitor availability:
Monitor your
/api/health
endpoint every 1-5 minutes.
使用外部服务监控可用性:
每隔1-5分钟监控你的
/api/health
端点。

Log Aggregation

日志聚合

Vercel:
  • Built-in log streaming
  • Integration with Datadog, LogDNA, Axiom
Railway:
  • Built-in logs in dashboard
  • Export to external services
Self-hosted:
bash
undefined
Vercel:
  • 内置日志流
  • 与Datadog、LogDNA、Axiom集成
Railway:
  • 控制台内置日志
  • 可导出到外部服务
自托管:
bash
undefined

Use Docker logging driver

使用Docker日志驱动

docker run --log-driver=json-file
--log-opt max-size=10m
--log-opt max-file=3
my-app
undefined
docker run --log-driver=json-file
--log-opt max-size=10m
--log-opt max-file=3
my-app
undefined

Database Migrations in CI/CD

CI/CD中的数据库迁移

Prisma Migrations

Prisma迁移

Run migrations before deployment:
GitHub Actions:
yaml
- name: Run migrations
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
Railway: Add to railway.json:
json
{
  "deploy": {
    "startCommand": "npx prisma migrate deploy && npm start"
  }
}
在部署前运行迁移:
GitHub Actions:
yaml
- name: Run migrations
  run: npx prisma migrate deploy
  env:
    DATABASE_URL: ${{ secrets.DATABASE_URL }}
Railway: 添加到railway.json:
json
{
  "deploy": {
    "startCommand": "npx prisma migrate deploy && npm start"
  }
}

Migration Safety

迁移安全

Never run destructive migrations automatically:
  1. Backwards compatible migrations first
    • Add new columns as nullable
    • Deploy code that works with old and new schema
    • Run migration
    • Deploy code that requires new schema
    • Remove old columns in future migration
  2. Manual approval for production
    yaml
    - name: Run migrations
      if: github.event_name == 'workflow_dispatch'
      run: npx prisma migrate deploy
切勿自动运行破坏性迁移:
  1. 先做向后兼容的迁移
    • 将新列设为可空
    • 部署兼容新旧 schema 的代码
    • 运行迁移
    • 部署依赖新 schema 的代码
    • 在后续迁移中删除旧列
  2. 生产环境需要手动批准
    yaml
    - name: Run migrations
      if: github.event_name == 'workflow_dispatch'
      run: npx prisma migrate deploy

Precision Tool Integration

精准工具集成

Validate Deployment with precision_exec

使用precision_exec验证部署

Use
precision_exec
to run deployment commands with expectations:
yaml
precision_exec:
  commands:
    - cmd: "npm run build"
      expect:
        exit_code: 0
    - cmd: "docker build -t my-app ."
      expect:
        exit_code: 0
    - cmd: "npm run typecheck"
      expect:
        exit_code: 0
  verbosity: minimal
使用
precision_exec
运行部署命令并验证结果:
yaml
precision_exec:
  commands:
    - cmd: "npm run build"
      expect:
        exit_code: 0
    - cmd: "docker build -t my-app ."
      expect:
        exit_code: 0
    - cmd: "npm run typecheck"
      expect:
        exit_code: 0
  verbosity: minimal

Health Check with precision_fetch

使用precision_fetch进行健康检查

Validate deployment health:
yaml
precision_fetch:
  requests:
    - url: "https://my-app.com/api/health"
      method: GET
      expect:
        status: 200
        body_contains: '"status":"healthy"'
验证部署健康状态:
yaml
precision_fetch:
  requests:
    - url: "https://my-app.com/api/health"
      method: GET
      expect:
        status: 200
        body_contains: '"status":"healthy"'

Discover Deployment Gaps

发现部署缺口

Before deploying, check for missing configuration:
yaml
discover:
  queries:
    - id: env_example
      type: glob
      patterns: [".env.example"]
    - id: dockerfile
      type: glob
      patterns: ["Dockerfile", "docker-compose.yml"]
    - id: ci_config
      type: glob
      patterns: [".github/workflows/*.yml"]
    - id: health_check
      type: grep
      pattern: '/api/health|/health'
      glob: "**/*.{ts,tsx,js,jsx}"
  output_mode: count_only
部署前检查缺失的配置:
yaml
discover:
  queries:
    - id: env_example
      type: glob
      patterns: [".env.example"]
    - id: dockerfile
      type: glob
      patterns: ["Dockerfile", "docker-compose.yml"]
    - id: ci_config
      type: glob
      patterns: [".github/workflows/*.yml"]
    - id: health_check
      type: grep
      pattern: '/api/health|/health'
      glob: "**/*.{ts,tsx,js,jsx}"
  output_mode: count_only

Pre-Deployment Checklist

部署前检查清单

Run the validation script:
bash
./plugins/goodvibes/skills/outcome/deployment/scripts/validate-deployment.sh /path/to/project
The script checks:
  1. Dockerfile exists
  2. .env.example exists and documents required variables
  3. CI/CD configuration present
  4. Health check endpoint implemented
  5. .dockerignore exists
  6. No hardcoded secrets in code
  7. Build command succeeds
  8. Database migration configuration present
运行验证脚本:
bash
./plugins/goodvibes/skills/outcome/deployment/scripts/validate-deployment.sh /path/to/project
该脚本检查以下内容:
  1. Dockerfile是否存在
  2. .env.example是否存在并记录了必需变量
  3. CI/CD配置是否存在
  4. 是否实现了健康检查端点
  5. .dockerignore是否存在
  6. 代码中是否存在硬编码的密钥
  7. 构建命令是否成功
  8. 数据库迁移配置是否存在

Common Pitfalls

常见陷阱

1. Missing Environment Variables

1. 缺失环境变量

Problem: Deployment fails because environment variables aren't set.
Solution: Document all variables in .env.example and validate at build time with zod.
问题: 因未设置环境变量导致部署失败。
解决方案: 在.env.example中记录所有变量,并使用zod在构建时验证。

2. Database Connection Pooling

2. 数据库连接池耗尽

Problem: Serverless functions exhaust database connections.
Solution: Use connection pooling (PgBouncer, Prisma Accelerate, Supabase pooler).
typescript
// Use connection pooler in serverless
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL, // Use pooled connection string
    },
  },
});
问题: 无服务器函数耗尽数据库连接。
解决方案: 使用连接池(PgBouncer、Prisma Accelerate、Supabase pooler)。
typescript
// 在无服务器环境中使用连接池
const prisma = new PrismaClient({
  datasources: {
    db: {
      url: process.env.DATABASE_URL, // 使用带连接池的连接字符串
    },
  },
});

3. Build Output Not Optimized

3. 构建输出未优化

Problem: Large Docker images, slow cold starts.
Solution: Use multi-stage builds, standalone output for Next.js, proper .dockerignore.
问题: Docker镜像过大,冷启动缓慢。
解决方案: 使用多阶段构建、Next.js的standalone输出、合理配置.dockerignore。

4. Migrations Run on Every Deploy

4. 每次部署都运行迁移

Problem: Prisma migrations run on every container start.
Solution: Separate migration step from app startup in CI/CD.
问题: Prisma迁移在每个容器启动时运行。
解决方案: 在CI/CD中将迁移步骤与应用启动分离。

5. No Rollback Plan

5. 无回滚计划

Problem: Bad deployment breaks production with no easy fix.
Solution: Use platforms with instant rollback (Vercel, Railway, Fly.io) or maintain previous Docker images.
问题: 错误的部署导致生产环境故障且无快速修复方案。
解决方案: 使用支持即时回滚的平台(Vercel、Railway、Fly.io)或保留旧的Docker镜像。

Summary

总结

Key Principles:
  1. Validate environment variables at build time - Fail fast, not in production
  2. Automate everything - CI/CD should handle lint, test, build, deploy
  3. Health checks are mandatory - Every service needs a health endpoint
  4. Preview deployments for every PR - Catch issues before merging
  5. Always have a rollback plan - Instant rollback > fixing forward
  6. Monitor from day one - Error tracking and uptime monitoring are not optional
  7. Migrations are dangerous - Run them carefully with backwards compatibility
Next Steps:
  1. Run
    validate-deployment.sh
    on your project
  2. Set up CI/CD pipeline with GitHub Actions
  3. Configure environment variables in your platform
  4. Add health check endpoint
  5. Test deployment to staging environment
  6. Deploy to production
  7. Set up monitoring and alerting
For detailed platform configurations and templates, see
references/deployment-platforms.md
.
核心原则:
  1. 在构建时验证环境变量 - 提前失败,而非在生产环境中出错
  2. 自动化所有流程 - CI/CD应处理代码检查、测试、构建、部署
  3. 健康检查是必需的 - 每个服务都需要健康端点
  4. 为每个PR创建预览部署 - 在合并前发现问题
  5. 始终制定回滚计划 - 即时回滚优于现场修复
  6. 从第一天开始监控 - 错误追踪和可用性监控不是可选的
  7. 迁移有风险 - 谨慎运行,确保向后兼容
下一步:
  1. 在你的项目上运行
    validate-deployment.sh
  2. 使用GitHub Actions设置CI/CD流水线
  3. 在平台中配置环境变量
  4. 添加健康检查端点
  5. 测试部署到预发布环境
  6. 部署到生产环境
  7. 设置监控与告警
如需详细的平台配置和模板,请查看
references/deployment-platforms.md