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 commit → git 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 更平滑。


下一步​

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