# 蓝绿部署计划 ## 当前问题 ``` 部署时: 停止服务 → 上传新代码 → 重启服务 → 跑迁移 ↑ 此时有停机时间(约 3-5 秒) ``` 单实例部署的风险:部署期间用户请求失败(502/503)。 ## 概念澄清 蓝绿部署仅用于**生产环境**,开发环境保持单实例: ``` 开发环境(dev.xmclassmate.top) — 单实例,无需蓝绿 └── 实例 :8080 └── 数据库 milkydata_dev 生产环境(xmclassmate.top) — 蓝绿部署 ├── 蓝色实例 :4433(当前活动) ├── 绿色实例 :4434(空闲) └── 数据库 milkydata(蓝绿共享,名称不变) ``` 开发环境不需要蓝绿的原因: | 原因 | 说明 | |------|------| | 停机时间可接受 | 开发环境只有开发者使用,重启 3-5 秒无影响 | | 简化运维 | 少维护一套 systemd service 和 nginx 配置 | | 快速迭代 | 直接 `deploy.sh development` 部署即可,无需切换步骤 | 生产环境使用蓝绿部署实现零停机发布。 ### 数据库与蓝绿的关系 数据库名称**不受蓝绿切换影响**: | 环境 | 数据库 | 蓝绿实例共同连接 | |------|--------|----------------| | 开发 | `milkydata_dev` | 单实例,无需蓝绿 | | 生产 | `milkydata` | `DATABASE_URL=postgres://.../milkydata` | 两个蓝绿实例的 service 文件中 `DATABASE_URL` 配置为完全相同的值。切换蓝绿时只改端口,不改数据库连接。 ## 域名与蓝绿的关系 蓝绿部署**不改变域名访问方式**,域名始终指向同一 OpenResty 实例: ``` 用户访问 OpenResty(域名不变) 后端实例 xmclassmate.top ──→ xmclassmate.top ──→ :4433(蓝)或 :4434(绿) ``` 切换时 OpenResty 内部的 `proxy_pass` 指向的目标端口变更,**用户无感知**: ``` 切换前:xmclassmate.top ──→ proxy_pass 127.0.0.1:4433 ← 蓝色活动 切换后:xmclassmate.top ──→ proxy_pass 127.0.0.1:4434 ← 绿色活动 ``` 小程序前端的 `env.ts` 中 `CURRENT_ENV=production` 指向 `xmclassmate.top`,蓝绿切换时**无需修改**。 ## 蓝绿部署架构(生产环境) ``` xmclassmate.top │ OpenResty proxy / \ 蓝色 (:4433 active) 绿色 (:4434 idle) rust-backend-blue rust-backend-green │ │ └──────────┬─────────────┘ ↓ milkydata(共享数据库) ``` 任何时候只有一个实例接收流量,另一个运行旧版本待命。 ## 组件变更 ### 新增 systemd service(生产环境) ``` /etc/systemd/system/ ├── rust-backend-blue.service ← 端口 4433 └── rust-backend-green.service ← 端口 4434 ``` 每个 service 配置与现有 `rust-backend.service` 一致,仅端口和描述不同,且 `DATABASE_URL` 指向 `milkydata`。 ### 新增 OpenResty 配置 由 1Panel 管理的 proxy 配置: ``` # /www/sites/xmclassmate.top/proxy/active-backend.conf location ^~ / { proxy_pass http://127.0.0.1:4433; # ← deploy.sh 切换此端口 ... } ``` 切换时 `sed` 替换端口号,然后 `nginx -s reload`。 ### 新增脚本 ``` scripts/ ├── deploy-blue-green.sh ← 蓝绿部署主脚本 └── switch-env.sh ← 手动切换/查看状态 ``` ## 部署流程(生产环境) ``` 初始状态:蓝色(:4433)=active 绿色(:4434)=idle 步骤 1:部署到空闲环境(绿色) ① 编译新代码 ② 上传二进制到绿色目录 ③ systemctl restart rust-backend-green.service ④ 运行数据库迁移 步骤 2:验证绿色环境 curl http://127.0.0.1:4434/health 运行 9 项部署测试 步骤 3:切换流量 sed 修改 OpenResty proxy_pass → 127.0.0.1:4434 nginx -s reload 步骤 4:验证切换后 curl https://xmclassmate.top/health 结果:绿色(:4434)=active 蓝色(:4433)=idle 下次部署时部署到蓝色 ``` ## 切换脚本 ```bash # 查看当前活动环境 ./scripts/switch-env.sh --status # → 生产环境: 蓝色 (127.0.0.1:4433) # 切换到绿色 ./scripts/switch-env.sh --env prod --switch green # → 修改 proxy_pass 127.0.0.1:4434 # → nginx -s reload # → 验证健康检查 ``` ## 数据库迁移注意事项 蓝绿部署中两个实例共享同一数据库(`milkydata`),迁移脚本需要对**新旧两个版本的代码都兼容**: | 迁移类型 | 兼容性 | 说明 | |---------|--------|------| | `CREATE TABLE` | ✅ | 新旧代码都能运行 | | `ADD COLUMN` | ✅ | 需 `DEFAULT` 或允许 `NULL` | | `RENAME COLUMN` | ❌ | 旧代码仍查旧列名 | | `DROP COLUMN` | ❌ | 旧代码查询被删列 | 对于不兼容的迁移(如列重命名),需要**三段式部署**: ``` 第 1 步:部署兼容双列名的代码(is_paid 和 is_member 同时支持) 第 2 步:执行迁移(重命名列) 第 3 步:部署只支持新列名的代码 ``` 当前代码已完成列重命名,若后续有类似变更需遵循此流程。 ## 实施优先级 | 阶段 | 内容 | 工作量 | |------|------|--------| | P1 | 创建两个 systemd service 模板(blue + green) | 小 | | P2 | 编写 `deploy-blue-green.sh` + `switch-env.sh` | 中 | | P3 | 实现 OpenResty proxy 配置切换 | 中 | | P4 | 改造 `deploy.sh` 支持 `--blue-green` | 中 | | P5 | 处理不兼容迁移的三段式部署文档 | 小 | | P6 | 编写回滚文档 | 小 | ## 回滚 ```bash # 新环境有问题 → 立即切回旧环境 ./scripts/switch-env.sh --env prod --switch blue # 旧环境代码未变,即时恢复 # 修复问题后重新部署到空闲环境 ``` ## 生产上线待办 前端切换到生产域名前,需要依次完成以下步骤: | # | 步骤 | 说明 | 执行方 | |---|------|------|--------| | 1 | **生产库跑迁移** | 在 `milkydata` 上执行 `010_rename_paid_fields.sql` 等缺失迁移 | 服务器操作 | | 2 | **准备生产 service 文件** | 填写 `deploy/rust-backend-prod.service` 中的实际值(JWT_SECRET、WECHAT_*、ALIPAY_*、DATABASE_URL) | 开发者 | | 3 | **部署生产后端** | `./deploy.sh production` 部署新代码到 `:4433` | 服务器操作 | | 4 | **修改前端 `CURRENT_ENV`** | `env.ts` 中 `CURRENT_ENV = 'production'`(当前已完成) | 开发者 | | 5 | **上传小程序** | 微信开发者工具上传代码(此时连 `xmclassmate.top`) | 开发者 | | 6 | **修改反向代理端口**(如需蓝绿) | 1Panel 中调整 `proxy_pass` 指向新端口 | 服务器操作 | ### 端口映射汇总 | 环境 | 域名 | 数据库 | 当前端口 | 蓝绿备选端口 | |------|------|--------|---------|-------------| | 开发 | `dev.xmclassmate.top` | `milkydata_dev` | `:8080` | 无(单实例) | | 生产 | `xmclassmate.top` | `milkydata` | `:4433` | `:4434` | ## 当前是否实施 当前项目规模(~100 日活),部署停机约 3-5 秒,实际影响可忽略。建议**保留文档**,当需要时再按 P1→P2 逐步实施。