deployment
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseResources
资源
scripts/
validate-deployment.sh
references/
deployment-platforms.mdscripts/
validate-deployment.sh
references/
deployment-platforms.mdDeployment
部署
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
undefinedInstall Vercel CLI
安装Vercel CLI
npm install -g vercel
npm install -g vercel
Deploy
部署
vercel --prod
**Environment variables:**
```bashvercel --prod
**环境变量:**
```bashSet production secrets
设置生产环境密钥
vercel env add DATABASE_URL production
vercel env add NEXTAUTH_SECRET production
undefinedvercel env add DATABASE_URL production
vercel env add NEXTAUTH_SECRET production
undefinedRailway (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
undefinedInstall 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
undefinedInstall Fly CLI
安装Fly CLI
curl -L https://fly.io/install.sh | sh
curl -L https://fly.io/install.sh | sh
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 = 256fly 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 = 256Docker (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
undefinedDatabase
数据库
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"
undefinedNEXT_PUBLIC_ENABLE_ANALYTICS="false"
undefinedEnvironment 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.ymlyaml
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.ymlyaml
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 baseInstall 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.mdBuild and Run
构建与运行
bash
undefinedbash
undefinedBuild 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
-e DATABASE_URL="postgresql://..."
-e NEXTAUTH_SECRET="..."
my-app
undefineddocker run -p 3000:3000
-e DATABASE_URL="postgresql://..."
-e NEXTAUTH_SECRET="..."
my-app
-e DATABASE_URL="postgresql://..."
-e NEXTAUTH_SECRET="..."
my-app
undefinedHealth 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 \
CMD node -e "require('http').get('http://localhost:3000/api/health', (r) => process.exit(r.statusCode === 200 ? 0 : 1))"在Dockerfile中添加健康检查:
dockerfile
HEALTHCHECK \
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: 10yaml
livenessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /api/health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10Preview 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
undefinedbash
undefinedList deployments
列出所有部署
vercel ls
vercel ls
Promote a previous deployment to production
将之前的部署升级为生产环境
vercel promote <deployment-url>
undefinedvercel promote <deployment-url>
undefinedBlue-Green Deployment
蓝绿部署
Deploy new version alongside old, then switch traffic:
bash
undefined在旧版本旁部署新版本,然后切换流量:
bash
undefinedDeploy new version (green)
部署新版本(绿色环境)
fly deploy --strategy bluegreen
fly deploy --strategy bluegreen
Traffic switches automatically after health checks pass
健康检查通过后自动切换流量
Rollback if needed:
需要时回滚:
fly releases rollback
undefinedfly releases rollback
undefinedCanary Deployment
金丝雀部署
Gradually shift traffic to new version:
Fly.io canary:
bash
undefined逐步将流量切换到新版本:
Fly.io金丝雀部署:
bash
undefinedDeploy canary (10% traffic)
部署金丝雀版本(10%流量)
fly deploy --strategy canary
fly deploy --strategy canary
Promote to 100% if successful
验证成功后升级为100%流量
fly releases promote
undefinedfly releases promote
undefinedMonitoring and Error Tracking
监控与错误追踪
Sentry Integration
Sentry集成
bash
npm install @sentry/nextjssentry.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/nextjssentry.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:
- Better Uptime: https://betteruptime.com
- Pingdom: https://www.pingdom.com
- UptimeRobot: https://uptimerobot.com
Monitor your endpoint every 1-5 minutes.
/api/health使用外部服务监控可用性:
- Better Uptime:https://betteruptime.com
- Pingdom:https://www.pingdom.com
- UptimeRobot:https://uptimerobot.com
每隔1-5分钟监控你的端点。
/api/healthLog Aggregation
日志聚合
Vercel:
- Built-in log streaming
- Integration with Datadog, LogDNA, Axiom
Railway:
- Built-in logs in dashboard
- Export to external services
Self-hosted:
bash
undefinedVercel:
- 内置日志流
- 与Datadog、LogDNA、Axiom集成
Railway:
- 控制台内置日志
- 可导出到外部服务
自托管:
bash
undefinedUse Docker logging driver
使用Docker日志驱动
docker run --log-driver=json-file
--log-opt max-size=10m
--log-opt max-file=3
my-app
--log-opt max-size=10m
--log-opt max-file=3
my-app
undefineddocker run --log-driver=json-file
--log-opt max-size=10m
--log-opt max-file=3
my-app
--log-opt max-size=10m
--log-opt max-file=3
my-app
undefinedDatabase 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:
-
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
-
Manual approval for productionyaml
- name: Run migrations if: github.event_name == 'workflow_dispatch' run: npx prisma migrate deploy
切勿自动运行破坏性迁移:
-
先做向后兼容的迁移
- 将新列设为可空
- 部署兼容新旧 schema 的代码
- 运行迁移
- 部署依赖新 schema 的代码
- 在后续迁移中删除旧列
-
生产环境需要手动批准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 to run deployment commands with expectations:
precision_execyaml
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_execyaml
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: minimalHealth 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_onlyPre-Deployment Checklist
部署前检查清单
Run the validation script:
bash
./plugins/goodvibes/skills/outcome/deployment/scripts/validate-deployment.sh /path/to/projectThe script checks:
- Dockerfile exists
- .env.example exists and documents required variables
- CI/CD configuration present
- Health check endpoint implemented
- .dockerignore exists
- No hardcoded secrets in code
- Build command succeeds
- Database migration configuration present
运行验证脚本:
bash
./plugins/goodvibes/skills/outcome/deployment/scripts/validate-deployment.sh /path/to/project该脚本检查以下内容:
- Dockerfile是否存在
- .env.example是否存在并记录了必需变量
- CI/CD配置是否存在
- 是否实现了健康检查端点
- .dockerignore是否存在
- 代码中是否存在硬编码的密钥
- 构建命令是否成功
- 数据库迁移配置是否存在
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:
- Validate environment variables at build time - Fail fast, not in production
- Automate everything - CI/CD should handle lint, test, build, deploy
- Health checks are mandatory - Every service needs a health endpoint
- Preview deployments for every PR - Catch issues before merging
- Always have a rollback plan - Instant rollback > fixing forward
- Monitor from day one - Error tracking and uptime monitoring are not optional
- Migrations are dangerous - Run them carefully with backwards compatibility
Next Steps:
- Run on your project
validate-deployment.sh - Set up CI/CD pipeline with GitHub Actions
- Configure environment variables in your platform
- Add health check endpoint
- Test deployment to staging environment
- Deploy to production
- Set up monitoring and alerting
For detailed platform configurations and templates, see .
references/deployment-platforms.md核心原则:
- 在构建时验证环境变量 - 提前失败,而非在生产环境中出错
- 自动化所有流程 - CI/CD应处理代码检查、测试、构建、部署
- 健康检查是必需的 - 每个服务都需要健康端点
- 为每个PR创建预览部署 - 在合并前发现问题
- 始终制定回滚计划 - 即时回滚优于现场修复
- 从第一天开始监控 - 错误追踪和可用性监控不是可选的
- 迁移有风险 - 谨慎运行,确保向后兼容
下一步:
- 在你的项目上运行
validate-deployment.sh - 使用GitHub Actions设置CI/CD流水线
- 在平台中配置环境变量
- 添加健康检查端点
- 测试部署到预发布环境
- 部署到生产环境
- 设置监控与告警
如需详细的平台配置和模板,请查看
references/deployment-platforms.md