Skip to main content

第八篇:上云 — CI/CD 与自动化部署

进入信号:部署本身在浪费你的时间,或者出过一次生产事故——客户在等,你不在电脑前。

本篇解决的问题:怎么把代码从一个本地 npm run dev 变成一个 7×24 可用的云服务?CI/CD 怎么从零搭建?多环境怎么管理?怎么选云平台?


那晚的事故

周六晚上 9 点,你在朋友家吃饭。G 发来消息:

「系统 502 了,明天周一要对账,今晚必须好。」

你打开手机,看不到日志,不知道发生了什么。你只能回复:「我在外面,大概一个半小时后到家,到了立刻修。」

G 回复:「好吧……」

那一个半小时你如坐针毡。到家后发现是 Supabase 连接池满了——10 个客户里有人导入了上万行的测试数据,把所有连接占满了。重启服务后恢复正常。但你永远忘不了 G 那句「好吧……」里的失望。

一次生产事故对客户信任的伤害,超过 10 次流畅体验建立的信任。 明天你再也不敢离开电脑了,但你也不可能 24 小时守在电脑前。

你需要让这个系统真正「上云」——不只是技术上部署到服务器,而是有一套机制让它持续可用。


第一步:环境体系搭建

直到现在,你只有两个环境:「本地开发(自己的笔记本)」和「生产环境(一台服务器)」。每次改完代码在本地测试,然后推到生产。这种模型一个人还能凑合,但已经开始出问题了:

  • 你没法在「和生产环境相同的配置」下测试
  • 一旦部署失败,客户直接受影响
  • 你想让一个客户先试试新功能,但只能全量发布

你需要多环境:

本地开发 (Local)         — 自己笔记本,随便折腾
↓ PR 提交
Preview 环境 (Preview) — 每个 Pull Request 自动部署,给客户预览
↓ 合并到 main
预发布环境 (Staging) — 和生产一模一样的环境,最后的验证
↓ 手动发布
生产环境 (Production) — 客户实际使用的环境

环境变量管理

每个环境有不同的数据库、不同的 API 密钥。你之前是把 .env 写死然后手动改。现在不能这样了:

# .env.local — 本地开发(不提交到 Git)
DATABASE_URL="postgresql://localhost:5432/reconciler_dev"

# .env.preview — Vercel Preview 环境变量
DATABASE_URL="postgresql://supabase:[email protected]:5432/reconciler_preview"

# .env.production — 生产环境
DATABASE_URL="postgresql://supabase:[email protected]:5432/reconciler_prod"

生产数据库和 Preview 数据库必须隔离——Preview 环境是用来测试的,上面会有脏数据、可能有破坏性操作。如果和生产共用数据库,一个测试脚本就能清掉客户的真实数据。


第二步:平台选型

你将现有代码从自己的一台 Linux 服务器,迁移到专业云平台。

前端:Vercel

你的前端是 Next.js,Vercel 是 Next.js 的母公司做的平台。

  • 天然支持 Next.js 的 ISR/SSR/App Router
  • 免费层够你撑到 10000 访问量/天
  • 它接管了 CDN、SSL、自定义域名

操作步骤:

  1. 在 Vercel 导入 GitHub 仓库
  2. 配好环境变量
  3. 设置 main 分支自动部署到 Production
  4. 配置自定义域名 app.reconcileflow.com
  5. Vercel 自动申请 SSL 证书,HTTPS 即刻生效

后端 API:保守策略

你的 API Routes 在 Next.js 里,天然和前端一起部署在 Vercel。对于现在的规模(几十个客户),全放 Vercel 完全够。不需要单独部署后端服务。

注意:Vercel 的 Serverless Function 有 10 秒超时限制。如果你的对账匹配需要处理超大文件(>30 秒),后续可能需要把匹配引擎拆到一个独立服务中。但现在不需要——现有客户没有超过 10 秒的匹配任务。

数据库:从 Supabase 免费层升级

免费层 500MB 即将不够。你升级到 Supabase Pro($25/月):

  • 8GB 空间
  • 自动备份(每天一次,保留 7 天)
  • 连接池(PgBouncer)——防止「连接数打满」的事故再次发生

文件存储(新增)

客户之前上传的 CSV 文件存在本地磁盘。上云后,Vercel 的 Serverless 环境没有持久化磁盘。你需要对象存储:

  • 方案:AWS S3 或 Cloudflare R2
  • R2 优势:不收流量费(S3 出站流量要付费),适合小规模
// 文件上传改为直接上传到 R2
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const r2 = new S3Client({
region: 'auto',
endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY!,
secretAccessKey: process.env.R2_SECRET_KEY!,
},
});

// 上传后拿到 URL,存到数据库
const url = `https://files.reconcileflow.com/${teamId}/${fileId}.csv`;

第三步:CI/CD 从零搭建

你受够了 ssh → git pull → npm run build → pm2 restart 的手动流程。现在是时候用 GitHub Actions 自动化了。

最小可行的 CI/CD 流水线

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

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

jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20' }
- run: npm ci
- run: npm run typecheck # TypeScript 类型检查
- run: npm run lint # ESLint 代码规范检查
- run: npm run test # 单元测试 + 集成测试
- run: npx prisma generate # 确保 Prisma Schema 没有语法错误

deploy-preview:
if: github.event_name == 'pull_request'
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- 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 }}
# Preview 部署,PR 评论里自动回链接

deploy-production:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- 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'

你的新部署流程:

  1. 改代码 → git commitgit push
  2. GitHub Actions 自动跑:TypeCheck → Lint → Test
  3. 如果全绿 → 自动部署到 Vercel Production
  4. 如果有 PR → 自动部署 Preview 环境,生成一个 xxx-preview.vercel.app 链接

从手动 5 分钟变成全自动 3 分钟,而且你可以在手机上完成。 以后在外面吃饭,收到 bug 报告,手机改一行代码 → push → 自动部署。再也不怕离开电脑了。

Preview 环境的妙用

当 G 说「能不能试试审批功能」时,你不再需要说「等上线以后」。你在一个 feature 分支上开发,GitHub 自动在 PR 里生成一个 Preview 链接:

「G,你试试这个链接,审批功能在这里。数据是测试数据,随便操作。」

Preview 环境让客户验收变成了一个自动化的流程,而不是让你给他开一个新服务器。


第四步:数据库迁移自动化

以前你手动 prisma db push。现在你有了 CI/CD,数据库迁移也需要自动化。

# .github/workflows/deploy.yml 中添加
- name: Run database migrations
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}

关键原则:永远在生产部署之前跑 Migration。如果 Migration 失败,部署就此中止,旧的代码还在跑。如果部署先跑了但 Migration 没跑,新代码可能访问不存在的表→ 500。

迁移的黄金法则

  1. 永远不要手动改生产数据库。所有 Schema 变更都通过 prisma migrate dev 生成 Migration 文件,提交到 Git
  2. Migration 文件要 Code Review。加一个字段看起来无害,但如果加了 NOT NULL 又没设默认值,Migration 就会把现有数据全毁掉
  3. 先跑备份,再跑 Migration。虽然 Supabase 有自动备份,但你在跑破坏性 Migration 之前手动备份一次,多一层保险

域名和 SSL

你之前一直用 http://12.34.56.78:3000 这种 IP 地址。现在需要一个专业的域名。

  • 买域名:reconcileflow.com(Namecheap/Cloudflare Registrar,$12/年)
  • DNS 指向 Vercel:在 Cloudflare 配 CNAME 记录
  • Vercel 自动签发 SSL 证书
  • app.reconcileflow.com → 产品主页
  • api.reconcileflow.com → API(如果需要独立出来)
  • 设置 www 301 重定向到裸域

给客户发链接的时候终于不用 12.34.56.78 了。


上云后的成本

服务用途费用/月
Vercel Pro前端 + API 部署$20
Supabase Pro数据库 + 备份$25
Cloudflare R2文件存储~$1(几百个 CSV)
GitHub ActionsCI/CD免费(公开仓库)
域名reconcileflow.com$1(折算月费)
合计$47/月

年付按折扣算下来大约 500/年。你的MRR现在是¥597×3=¥1,791/500/年。你的 MRR 现在是 ¥597 × 3 = ¥1,791/月 ≈ 250/月。基础设施成本占收入的 20% 左右,健康比例。


什么时候进入下一阶段?

你已经做到了:

  • ✅ CI/CD 全自动:Push → 自动检查 → 自动部署
  • ✅ 多环境:Local / Preview / Staging / Production
  • ✅ 数据库自动备份 + Migration 自动化
  • ✅ 域名 + SSL + CDN,专业级体验
  • ✅ 基础设施月费 $47,占收入 20%

你的客户增长到了约 50 个,MRR 到了约 ¥10,000/月。业务稳定了。

但是新的信号出现了:

  • 某个周一早上,数据库突然变慢——一个客户的对账查询跑了 30 秒,影响了其他所有客户
  • 你第一次是从客户那里得知系统变慢了(而不是从监控面板),因为你还没有监控
  • G 问你:「你们的 SLA 是多少?如果我们周一上午对账高峰期系统挂了,能保证多长时间恢复?」

进入下一阶段的信号:以下任一——

  • 客户的生产环节依赖你的系统,你挂他们也挂
  • 你第一次从客户那里得知系统出了故障(而不是自己先发现)

这是第九篇的内容——专业化。


本篇总结

做了什么花了多久
多环境搭建(Local/Preview/Staging/Production)半天
Vercel + Supabase 迁移1 天
Cloudflare R2 文件存储2 小时
GitHub Actions CI/CD半天
域名 + SSL1 小时
数据库 Migration 自动化1 小时

当前系统形态: 有 CI/CD、有多环境管理、能自动部署的云服务。前端 Vercel + 数据库 Supabase + 文件 R2。50 个客户,不再需要手动 SSH。

**本月账单:47/Vercel47/月**(Vercel 20 + Supabase 25+R225 + R2 1 + 域名 $1)。MRR ¥10,000/月。

如果是 ToC: 这个阶段基础设施成本会更低——你的前端和 API 放 Vercel Hobby(免费),数据库用 Supabase 免费层。等到 1000+ 用户再升级。ToC 的规模化靠用户量撑,基础设施成本增长比 ToB 更平滑。


下一步

客户依赖你的生产环境——进入第九篇:专业化,监控、日志、缓存、安全从「没有」到「可依赖」。