跳到主要内容跳到导航跳到页脚
看山AI实验室

Next.js GitHub Actions 生产部署流水线:自动 patch、迁移与部署通知

从 Jenkins 到 GitHub Actions:一人产品的 Next.js 生产部署流水线实战

本文基于一个真实的 Next.js 全栈项目(相册 / SaaS 类应用)的 CI/CD 改造经验整理,已脱敏:不含服务器 IP、密钥内容、内网地址或任何可复用的凭证。目标是给「一个人做产品、自托管 VPS、想少踩坑」的开发者一份可照抄架构、自行填配置的参考。


背景:我们之前怎么部署?

早期方案是 Jenkins + 本地触发脚本

  • 开发者在本地跑 deploy.sh,脚本负责 lint、build、打 tar 包、SCP 上传、远端 PM2 重启
  • Jenkins 只是「远程按钮」,和 Git 没有强绑定
  • 部署记录散落在本地日志目录,很难回答「生产现在跑的是哪个 commit?」

随着功能迭代加速(体验官运营闭环、账户页改版等),这套方式的短板越来越明显:

  1. merge 不等于上线 — 容易忘记手动部署
  2. 数据库迁移靠记忆 — 某次忘了 prisma migrate deploy,线上 schema 滞后
  3. 没有统一的部署通知 — 成功了没人知道,失败了更没人知道
  4. 版本号对用户和运营不可见 — 排障时要 SSH 上去查 .deploy-commit

于是我们做了三件事:用 GitHub Actions 替代 Jenkins补齐部署后链路(迁移 / 版本 / 通知)在账户页低调展示版本号


总体架构:双轨 CI/CD

轨道触发职责
CIPR → main质量门禁:pnpm lint + pnpm build,不部署
CDpush main自动 patch、构建、上传、迁移、重启、通知

PR 阶段只验证「能不能合」,合进去才动生产——这是小团队最省心的分界。


生产部署 Workflow 分步拆解

1. 跳过条件:避免无限循环

merge 后会自动 bump 版本并 再 push 一个 commitchore(version): bump patch to x.y.z [skip ci])。因此 Workflow 必须跳过两类提交:

  • commit message 含 [skip ci]
  • message 以 chore(version): 开头

否则会出现:部署 → bump commit → 再次触发部署 → 再 bump 的死循环。

2. 自动 patch 版本(semver 第三位)

策略:每次 merge main,patch +1;minor/major 仍由人工发版。

Workflow 顺序是:

  1. 先 bump(工作区 package.json 变为新版本,尚未 commit)
  2. 再 build + deploy(线上跑的是新版本号)
  3. 部署成功后github-actions[bot] commit + push bump 结果,并带 [skip ci]

这样 Git 历史里能清楚看到「哪次部署对应哪个 semver」,同时不会重复触发流水线。

3. Secrets 与 Variables(脱敏清单)

Secrets(敏感,不进仓库):

名称用途
PROD_SSH_PRIVATE_KEY部署用 SSH 私钥
PROD_ENV_FILE生产环境完整 .env 内容
OPC_FEED_API_TOKENOPC Feed REST/MCP 个人 API 令牌

Variables(非敏感,可公开配置名):

名称用途
LIFEFRAME_PROD_URL生产站点 URL(health / 通知链接)
OPC_FEED_API_URLOPC API 根地址
OPC_DEPLOY_PARENT_EVENT_ID部署事件的父节点 ID(时间线分组)

Runner 上通过 SSH config 挂载私钥,不要在日志里 echo 密钥;.env 由 Secret 一次性写入工作区,随 tar 包带到服务器。

4. deploy.sh:一条脚本打通本地与 CI

核心思路:GitHub Actions 和开发者本地共用同一个 deploy.sh,避免「CI 一套、手工又一套」。

本地阶段:

  • pnpm installpnpm lint(可配置失败是否中止)→ pnpm build
  • 构建前注入版本信息:
  • .nextpackage.jsonprisma/ 等打入 tar.gz

远端阶段(SSH 远程 bash):

  1. 备份旧 .next,解压新包
  2. 写入 .deploy-commit(供 /api/health 读取)
  3. pnpm install --prod --frozen-lockfile
  4. pnpm prisma migrate deploy ← 本次改造的关键补齐
  5. pnpm prisma generate
  6. PM2 重启应用 + 三个后台 worker
  7. curl /api/health 轮询,超时则失败退出

migrate 失败即中止、不重启 PM2,避免「半新半旧」的灾难状态。

5. 构建 OOM 防护

GitHub-hosted runner 默认 Node 堆约 2GB,Next.js 生产 build + Sentry source map 容易 OOM。我们在 CI 里显式设置:

这是「能稳定跑完 6 分钟部署」的实际经验,不是过度优化。


账户页版本号:低调但有用

产品决策:只在 /account 底部显示,不对公开落地页打扰。

数据来源:

  • NEXT_PUBLIC_APP_VERSION — build 时从 package.json 注入
  • NEXT_PUBLIC_GIT_COMMIT — build 时从 git rev-parse --short HEAD 注入
  • 本地 dev 回退为 v0.2.x · dev(在 next.config.jsenv 字段配置)

用户截图账户页底部,客服/开发就能立刻对齐「他看到的是不是最新部署」。

服务端 /api/health 仍返回 { ok: true, commit }(读 .deploy-commitDEPLOY_GIT_COMMIT),供脚本探活,不依赖数据库


OPC Feed:部署结果写进时间线 + 推 IM

OPC Feed 是我们另一个项目——面向 AI Agent 与一人公司的项目时间线。这次把它接进部署通知,而不是再造一套 Slack/飞书 Webhook。

为什么用 OPC 而不是裸 Webhook?

能力裸 WebhookOPC Feed
即时 IM✅(钉钉/飞书/企微等)
可追溯时间线✅ 按项目归档
与开发记录同屏✅ 和里程碑、决策放一起
Agent 可读上下文✅ MCP + REST

实现方式

CI 末尾增加一步(continue-on-error: true,通知失败不应掩盖部署成败):

要点:

  • typeSlug: deployment — 平台内置「部署」类型,和 OPC 自家 prod 流水线一致
  • notifyOnCreate: true — 成功也推 IM(我们选的策略;也可改为仅失败推送)
  • 父事件 — 先手动建一条「XX 生产部署跟踪」,后续每次部署挂为子事件,时间线不散
  • Token 缺失时 exit 0 — 不影响部署主路径,方便 Fork 或未配置 OPC 的环境

失败分支用 if: failure() 再跑同一脚本,传 DEPLOY_STATUS=failureimportance 更高、标题带 ❌。


一次完整 merge 的时间线


与 Jenkins 退役的对比

维度Jenkins 时代GitHub Actions 现在
触发手动 / 定时merge main 自动
与 Git 关系强(SHA、PR、Workflow run 链接)
版本号无自动 bumppatch 自动 + 回写 commit
DB 迁移靠人工migrate deploy 内置
通知OPC 时间线 + IM
运维成本需维护 Jenkins 实例零额外服务器

Jenkinsfile 删除后,部署文档归档到 docs/archive/deployment/,主路径文档指向 GitHub Actions 指南。


你可以直接抄走的 Checklist

基础设施

  • 生产机 SSH 密钥对 + 仅允许 GitHub Actions IP 或 bastion
  • Secrets:PROD_SSH_PRIVATE_KEYPROD_ENV_FILE
  • VPS 安装 Node 22、pnpm、PM2、curl

Workflow

  • PR:ci.yml lint + build
  • main:deploy-prod.yml + [skip ci] 防循环
  • permissions: contents: write 用于 bump commit

deploy.sh

  • 构建注入 NEXT_PUBLIC_* 版本 env
  • 远端 prisma migrate deploy 在 generate 之前
  • health check 失败则 exit 1

可观测性

  • /api/health 返回 commit
  • 账户页或设置页版本 badge
  • OPC / Webhook 部署通知(continue-on-error: true

常见坑

  1. bump commit 触发二次部署 — 必须 [skip ci] + Workflow if 过滤 chore(version):
  2. migrate 在 PM2 重启之后 — 顺序错了会出现新代码连旧 schema
  3. 通知 step 失败导致整个 Workflow 红 — 用 continue-on-error: true
  4. 把 Secret 写进日志 — SSH key、.env 只通过 env 注入,禁止 echo
  5. Runner OOM — Next.js 生产 build 建议 4GB 堆 + 关 source map 上传

小结

这次改造的本质不是「换成 GitHub Actions 更潮」,而是把一人产品最缺的四件事补上了:

  1. merge 即部署 — 减少人为遗漏
  2. 迁移自动化 — 减少 schema 漂移
  3. 版本可读 — 用户、运营、开发对齐同一事实
  4. 部署可感知 — 时间线 + IM,成功失败都有记录

如果你也在维护 Next.js + 自托管 + Prisma 的项目,可以直接复用「双轨 Workflow + 单脚本 deploy.sh + health 探活 + 可选 OPC 通知」这套骨架,把 Secrets 和域名换成自己的即可。


本文对应开源仓库的一次 CI/CD 改造(Jenkins 退役 + 自动 patch + OPC 部署通知 + 账户页版本号)。架构与脚本思路可复用;具体 IP、密钥与内网配置请自行替换,切勿在公开场合粘贴生产 Secret。