6.1 KiB
6.1 KiB
自动构建与自动重启流程
本文档说明当前项目通过 Git remote + post-receive hook 实现自动构建、自动重启的流程。核心文件为 .githooks/post-receive。
部署入口
当前涉及两个服务器 remote:
| 环境 | Git remote | 推送分支 | 服务端端口 | 部署脚本 |
|---|---|---|---|---|
| 测试环境 | test |
test |
9135 |
scripts/deploy/deploy_web_test.sh |
| 生产环境 | production |
main |
9185 |
scripts/deploy/deploy_web.sh |
当前 remote 配置示例:
test root@43.106.13.130:/root/cozsweet-repos/test
production root@43.106.13.130:/root/cozsweet-repos/main
常用发布入口:
# 发布测试环境
./scripts/release/pre_release_web.sh
# 发布生产环境
./scripts/release/release_web.sh
也可以只执行推送脚本:
# 推送 test remote 的 test 分支
./scripts/deploy/deploy_web_test.sh
# 推送 production remote 的 main 分支
./scripts/deploy/deploy_web.sh
本地发布流程
测试环境发布流程:
- 进入 test worktree:
cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-test - 确认当前分支。
- 执行
git rebase dev,把dev的最新代码变基到test分支。 - 复制测试环境图标到
public/。 - 复制
env-example/.env.local.example到.env.local。 - 执行
scripts/deploy/deploy_web_test.sh。 deploy_web_test.sh推送testremote 的test分支。- 推送成功后尝试清除 Cloudflare CDN 缓存。
生产环境发布流程:
- 进入 main worktree:
cozsweet-frontend-nextjs.worktrees/cozsweet-nextjs-main - 确认当前分支。
- 执行
git rebase dev,把dev的最新代码变基到main分支。 - 复制生产环境图标到
public/。 - 复制
env-example/.env.production.example到.env.production。 - 执行
scripts/deploy/deploy_web.sh。 deploy_web.sh强制推送productionremote 的main分支。- 推送成功后尝试清除 Cloudflare CDN 缓存。
服务器端 post-receive 流程
服务器收到 push 后,post-receive hook 会自动执行以下步骤:
- 初始化 Node / pnpm 环境。
- 解析当前仓库目录,进入服务端工作树。
- 初始化日志文件:
logs/post-receive.log。 - 覆盖写入本次执行元信息,包括时间、分支、commit、cwd。
- 执行
git reset --hard HEAD,让服务端工作树同步到刚推送的最新 commit。 - 根据当前分支复制环境变量文件。
- 根据当前分支选择 Next.js 启动端口。
- 执行
pnpm run build:deploy。 - 如果构建失败,写入失败日志并中止,不会重启服务。
- 如果构建成功,查找并强杀当前端口上的旧 Next.js 进程。
- 等待端口释放,并重试确认。
- 端口释放成功后,执行
nohup pnpm run start后台启动新服务。
分支、环境变量、端口映射
post-receive 当前按服务端工作树所在分支判断环境:
| 服务端分支 | 环境变量复制 | 启动端口 |
|---|---|---|
main |
env-example/.env.production.example → .env.production |
9185 |
test |
env-example/.env.local.example → .env.local |
9135 |
dev |
env-example/.env.development.example → .env.local |
9135 |
| 其他分支 | 跳过 env 复制 | 9135 |
本地生产发布脚本和服务器端 post-receive 已统一使用 .env.production。Next.js 在生产构建时会读取 .env.production;测试和开发发布仍使用 .env.local。
本地部署脚本清除 Cloudflare CDN 缓存时,也会按当前分支读取 env:main 优先读取 .env.production,其他分支优先读取 .env.local。如果优先文件不存在或缺少 CF_ZONE_ID / CF_API_TOKEN,会尝试读取另一个文件作为兜底。
自动重启机制
重启由 post-receive 中的端口进程管理实现:
- 使用
ss -tulnp查询占用目标端口的进程。 - 如果找到旧进程,执行
kill -9强制停止。 - 默认等待
3秒。 - 最多重试
3次确认端口已经释放。 - 如果端口仍未释放,中止启动,避免新服务出现
EADDRINUSE。 - 如果端口释放成功,执行:
PORT="$START_PORT" nohup pnpm run start >> "$LOG_FILE" 2>&1 &
package.json 中的 start 脚本会优先使用传入的 PORT,因此测试环境固定使用 9135,生产环境固定使用 9185。
日志与排查
服务器端日志文件:
logs/post-receive.log
当前日志策略是每次 post-receive 执行时覆盖旧日志,而不是追加。
常见排查命令:
# 查看最近一次部署日志
tail -n 200 logs/post-receive.log
# 查看端口占用
ss -tulnp | grep ':9135'
ss -tulnp | grep ':9185'
# 查看当前分支和 commit
git branch --show-current
git rev-parse --short HEAD
构建失败时,日志中会出现:
build EXIT_CODE=<非 0>
ABORTED ... (build failed, start skipped)
这种情况下不会停止旧服务,也不会启动新服务。
端口释放失败时,日志中会出现:
stop FAILED: port <端口> still occupied
这种情况下不会启动新服务,需要人工检查占用该端口的进程。
关键约束
scripts/deploy/*只负责推送代码,不负责本地构建和本地启动。- 自动构建和自动重启只发生在服务器端
post-receivehook。 main分支对应生产环境,test分支对应测试环境。- 生产推送当前使用
git push --force production main。 - 构建失败时不会启动新服务,避免用旧
.next跑新代码。 - 服务启动使用
nohup后台进程,不依赖 PM2 或 systemd。
后续优化建议
- 将服务进程交给 PM2 或 systemd 管理,提升崩溃自动恢复能力。
- 保留最近 N 次部署日志,而不是只保留最后一次日志,方便排查历史问题。
- 构建命令可以保留完整输出到单独日志文件,当前
pnpm run build:deploy输出被丢弃,只记录退出码。 - 可以在启动后增加健康检查,确认新服务真正可访问后再判定部署成功。