关于 deployment-automation
面向在生产环境运行 Next.js 应用的团队,汇集 Vercel 部署、GitHub Actions CI/CD、环境管理、检查、监控及回滚指南。
主要功能
- 01Vercel 生产与预览部署
- 02GitHub Actions CI/CD 示例
- 03环境变量管理
- 04部署前检查与数据库迁移
- 05监控与回滚策略
- 06功能标记与性能预算
适用场景
- 01设置 Next.js 自动部署
- 02为拉取请求配置预览构建
- 03发布前运行检查与迁移
- 04规划生产环境回滚流程
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill deployment-automation安装后在 Claude Code 中输入/deployment-automation确认已加载。
详细介绍
部署自动化技能
概述
此技能可帮助你在生产环境中部署和管理 Next.js 应用。从 Vercel 部署到 CI/CD 流水线,这里涵盖了实现顺畅自动化部署所需的一切。
Vercel 部署
安装 Vercel CLI
npm i -g vercel
vercel login
部署到生产环境
# Deploy to production
vercel --prod
# Deploy with specific environment
vercel --prod --env production
从 Git 部署
# Link project
vercel link
# Auto-deploy on git push (configured in Vercel dashboard)
git push origin main # Auto-deploys to production
git push origin develop # Auto-deploys to preview
项目配置
// vercel.json
{
"buildCommand": "npm run build",
"devCommand": "npm run dev",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"], // AWS us-east-1
"env": {
"NEXT_PUBLIC_APP_URL": "https://myapp.com"
},
"build": {
"env": {
"NEXT_PUBLIC_VERCEL_ENV": "@vercel-env"
}
},
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
}
]
}
],
"redirects": [
{
"source": "/old-page",
"destination": "/new-page",
"permanent": true
}
],
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://api.backend.com/:path*"
}
]
}
环境变量
使用 Vercel CLI:
# Add production env var
vercel env add SUPABASE_URL production
# Add to all environments
vercel env add DATABASE_URL
# Pull env vars locally
vercel env pull .env.local
使用 Vercel 控制面板:
- 前往 Project Settings → Environment Variables
- 为每个环境添加变量:
- Production
- Preview
- Development
加密密钥:
# Add sensitive data
vercel secrets add database-url "postgresql://..."
# Reference in vercel.json
{
"env": {
"DATABASE_URL": "@database-url"
}
}
特定环境配置
// lib/config.ts
const config = {
development: {
apiUrl: 'http://localhost:3000/api',
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
},
preview: {
apiUrl: process.env.NEXT_PUBLIC_API_URL!,
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
},
production: {
apiUrl: 'https://api.myapp.com',
supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
},
}
const env = (process.env.NEXT_PUBLIC_VERCEL_ENV || 'development') as keyof typeof config
export const appConfig = config[env]
GitHub Actions CI/CD
基本工作流
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
jobs:
test:
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 dependencies
run: npm ci
- name: Run linter
run: npm run lint
- name: Run type check
run: npm run type-check
- name: Run tests
run: npm test
- name: Build
run: npm run build
env:
NEXT_PUBLIC_SUPABASE_URL: ${{ secrets.NEXT_PUBLIC_SUPABASE_URL }}
NEXT_PUBLIC_SUPABASE_ANON_KEY: ${{ secrets.NEXT_PUBLIC_SUPABASE_ANON_KEY }}
从 GitHub Actions 部署到 Vercel
# .github/workflows/deploy.yml
name: Deploy to Vercel
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
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'
在 PR 上运行测试
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
quality:
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 dependencies
run: npm ci
- name: Lint
run: npm run lint
- name: Type check
run: npm run type-check
- name: Unit tests
run: npm test
- name: E2E tests
run: npx playwright test
- name: Upload test results
if: always()
uses: actions/upload-artifact@v3
with:
name: playwright-report
path: playwright-report/
retention-days: 30
部署前检查
自定义部署前脚本
// package.json
{
"scripts": {
"predeploy": "npm run check:all",
"check:all": "npm run lint && npm run type-check && npm test",
"lint": "next lint",
"type-check": "tsc --noEmit",
"test": "jest"
}
}
健康检查端点
// app/api/health/route.ts
import { NextResponse } from 'next/server'
export async function GET() {
try {
// Check database connection
await db.$queryRaw`SELECT 1`
// Check external services
const services = await Promise.allSettled([
fetch(process.env.API_URL!),
fetch(process.env.SUPABASE_URL!),
])
const allHealthy = services.every(s => s.status === 'fulfilled')
return NextResponse.json({
status: allHealthy ? 'healthy' : 'degraded',
timestamp: new Date().toISOString(),
version: process.env.NEXT_PUBLIC_APP_VERSION,
services: {
database: 'healthy',
api: services[0].status === 'fulfilled' ? 'healthy' : 'unhealthy',
supabase: services[1].status === 'fulfilled' ? 'healthy' : 'unhealthy',
}
})
} catch (error) {
return NextResponse.json(
{ status: 'unhealthy', error: error.message },
{ status: 503 }
)
}
}
数据库迁移
部署时运行迁移
// package.json
{
"scripts": {
"build": "npm run db:migrate && next build",
"db:migrate": "npx supabase db push"
}
}
安全迁移策略
# 1. Test migration locally
npx supabase db reset
npx supabase db push
# 2. Create backup
npx supabase db dump > backup.sql
# 3. Apply to production
npx supabase db push --linked
# 4. Verify
curl https://myapp.com/api/health
监控与警报
Vercel Speed Insights
// app/layout.tsx
import { SpeedInsights } from '@vercel/speed-insights/next'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<SpeedInsights />
</body>
</html>
)
}
Vercel Analytics
import { Analytics } from '@vercel/analytics/react'
export default function RootLayout({ children }) {
return (
<html>
<body>
{children}
<Analytics />
</body>
</html>
)
}
自定义监控
// lib/monitoring.ts
export async function reportDeployment() {
if (process.env.NODE_ENV === 'production') {
await fetch('https://monitoring.example.com/deployments', {
method: 'POST',
body: JSON.stringify({
version: process.env.NEXT_PUBLIC_APP_VERSION,
timestamp: new Date().toISOString(),
environment: process.env.NEXT_PUBLIC_VERCEL_ENV,
}),
})
}
}
// Call in app initialization
reportDeployment()
功能标志
基于环境的标志
// lib/features.ts
export const features = {
newDesign: process.env.NEXT_PUBLIC_FEATURE_NEW_DESIGN === 'true',
betaFeatures: process.env.NEXT_PUBLIC_FEATURE_BETA === 'true',
analytics: process.env.NEXT_PUBLIC_FEATURE_ANALYTICS === 'true',
}
// Usage
import { features } from '@/lib/features'
export function Component() {
if (!features.newDesign) {
return <OldDesign />
}
return <NewDesign />
}
高级功能标志(Vercel Edge Config)
import { get } from '@vercel/edge-config'
export async function getFeatureFlag(key: string): Promise<boolean> {
try {
return await get<boolean>(key) ?? false
} catch {
return false
}
}
// Usage in Server Component
export default async function Page() {
const showNewFeature = await getFeatureFlag('new-feature')
if (showNewFeature) {
return <NewFeature />
}
return <OldFeature />
}
回滚策略
即时回滚
# List deployments
vercel ls
# Promote previous deployment to production
vercel promote <deployment-url>
出错时自动回滚
# .github/workflows/deploy-with-rollback.yml
name: Deploy with Rollback
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get previous deployment
id: prev-deploy
run: |
PREV_URL=$(vercel ls --token=${{ secrets.VERCEL_TOKEN }} | grep production | head -n 2 | tail -n 1 | awk '{print $2}')
echo "prev_url=$PREV_URL" >> $GITHUB_OUTPUT
- name: Deploy to Vercel
id: deploy
run: |
URL=$(vercel --prod --token=${{ secrets.VERCEL_TOKEN }})
echo "deploy_url=$URL" >> $GITHUB_OUTPUT
- name: Health check
id: health
run: |
sleep 10
STATUS=$(curl -s -o /dev/null -w "%{http_code}" ${{ steps.deploy.outputs.deploy_url }}/api/health)
if [ $STATUS -ne 200 ]; then
echo "Health check failed"
exit 1
fi
- name: Rollback on failure
if: failure()
run: |
vercel promote ${{ steps.prev-deploy.outputs.prev_url }} --token=${{ secrets.VERCEL_TOKEN }}
预览部署
自动生成预览 URL
每次推送分支都会获得一个唯一 URL:
https://myapp-git-feature-branch-username.vercel.app
在 PR 中添加预览评论
# .github/workflows/preview-comment.yml
name: Preview Deployment Comment
on:
deployment_status:
jobs:
comment:
if: github.event.deployment_status.state == 'success'
runs-on: ubuntu-latest
steps:
- name: Comment PR
uses: actions/github-script@v6
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `✅ Preview deployed to ${process.env.DEPLOYMENT_URL}`
})
性能预算
Lighthouse CI
# .github/workflows/lighthouse.yml
name: Lighthouse CI
on:
pull_request:
branches: [main]
jobs:
lighthouse:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v10
with:
urls: |
https://preview-url.vercel.app
https://preview-url.vercel.app/dashboard
uploadArtifacts: true
temporaryPublicStorage: true
Bundle 大小检查
# .github/workflows/bundle-size.yml
name: Bundle Size Check
on: [pull_request]
jobs:
size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Check bundle size
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
最佳实践检查清单
- 使用环境变量保存密钥
- 设置从 Git 自动部署
- 为 PR 配置预览部署
- 实现健康检查端点
- 设置监控和警报
- 部署前运行测试
- 使用功能标志逐步发布
- 制定回滚策略
- 监控 Core Web Vitals
- 设置性能预算
- 安全地运行数据库迁移
- 使用独立环境(dev/staging/prod)
- 实现完善的错误跟踪
- 记录部署流程
何时使用此技能
在以下情况下调用此技能:
- 首次部署到 Vercel
- 设置 CI/CD 流水线
- 配置环境变量
- 实现功能标志
- 设置监控
- 制定回滚策略
- 优化部署速度
- 调试生产环境问题
- 管理预览部署
- 设置自动化测试
评论
支持 Markdown