217 lines
6.6 KiB
Markdown
217 lines
6.6 KiB
Markdown
# 蓝绿部署计划
|
||
|
||
## 当前问题
|
||
|
||
```
|
||
部署时: 停止服务 → 上传新代码 → 重启服务 → 跑迁移
|
||
↑
|
||
此时有停机时间(约 3-5 秒)
|
||
```
|
||
|
||
单实例部署的风险:部署期间用户请求失败(502/503)。
|
||
|
||
## 概念澄清
|
||
|
||
蓝绿部署是**同一环境内的两个实例**,不是跨环境:
|
||
|
||
```
|
||
开发环境(dev.xmclassmate.top)
|
||
├── 蓝色实例 :8080(当前活动)
|
||
├── 绿色实例 :8081(空闲)
|
||
└── 数据库 milkydata_dev(共享)
|
||
|
||
生产环境(xmclassmate.top)
|
||
├── 蓝色实例 :4433(当前活动)
|
||
├── 绿色实例 :4434(空闲)
|
||
└── 数据库 milkydata(共享)
|
||
```
|
||
|
||
每个环境独立维护自己的蓝绿实例,互不干扰。
|
||
|
||
## 蓝绿部署架构
|
||
|
||
以开发环境为例:
|
||
|
||
```
|
||
dev.xmclassmate.top
|
||
│
|
||
OpenResty proxy
|
||
/ \
|
||
蓝色 (:8080 active) 绿色 (:8081 idle)
|
||
rust-backend-blue rust-backend-green
|
||
| |
|
||
└──────────┬─────────────┘
|
||
↓
|
||
milkydata_dev(共享数据库)
|
||
```
|
||
|
||
任何时候只有一个实例接收流量,另一个运行旧版本待命。
|
||
|
||
## 域名与蓝绿的关系
|
||
|
||
蓝绿部署**不改变域名访问方式**,域名始终指向同一 OpenResty 实例:
|
||
|
||
```
|
||
用户访问 OpenResty(域名不变) 后端实例
|
||
dev.xmclassmate.top ──→ dev.xmclassmate.top ──→ :8080(蓝)或 :8081(绿)
|
||
xmclassmate.top ──→ xmclassmate.top ──→ :4433(蓝)或 :4434(绿)
|
||
```
|
||
|
||
切换时 OpenResty 内部的 `proxy_pass` 指向的目标端口变更,**用户无感知**:
|
||
|
||
```
|
||
切换前:dev.xmclassmate.top ──→ proxy_pass 127.0.0.1:8080 ← 蓝色活动
|
||
切换后:dev.xmclassmate.top ──→ proxy_pass 127.0.0.1:8081 ← 绿色活动
|
||
```
|
||
|
||
小程序前端的 `env.ts` 中 `CURRENT_ENV` 指向的域名(`dev.xmclassmate.top` 或 `xmclassmate.top`)**无需修改**。
|
||
|
||
## 组件变更
|
||
|
||
### 新增 systemd service
|
||
|
||
```
|
||
/etc/systemd/system/
|
||
├── rust-backend-dev-blue.service ← 端口 8080
|
||
└── rust-backend-dev-green.service ← 端口 8081
|
||
```
|
||
|
||
生产环境同理:
|
||
|
||
```
|
||
/etc/systemd/system/
|
||
├── rust-backend-blue.service ← 端口 4433
|
||
└── rust-backend-green.service ← 端口 4434
|
||
```
|
||
|
||
每个 service 配置与现有文件一致,仅端口和描述不同,且 `DATABASE_URL` 指向同一数据库。
|
||
|
||
### 新增 OpenResty 配置
|
||
|
||
由 1Panel 管理的 proxy 配置:
|
||
|
||
```
|
||
# /www/sites/dev.xmclassmate.top/proxy/active-backend.conf
|
||
|
||
location ^~ / {
|
||
proxy_pass http://127.0.0.1:8080; # ← deploy.sh 切换此端口
|
||
...
|
||
}
|
||
```
|
||
|
||
切换时 `sed` 替换端口号,然后 `nginx -s reload`。
|
||
|
||
### 新增脚本
|
||
|
||
```
|
||
scripts/
|
||
├── deploy-blue-green.sh ← 蓝绿部署主脚本
|
||
└── switch-env.sh ← 手动切换/查看状态
|
||
```
|
||
|
||
## 部署流程
|
||
|
||
```
|
||
初始状态:蓝色(:8080)=active 绿色(:8081)=idle
|
||
|
||
步骤 1:部署到空闲环境(绿色)
|
||
① 编译新代码
|
||
② 上传二进制到绿色目录
|
||
③ systemctl restart rust-backend-dev-green.service
|
||
④ 运行数据库迁移
|
||
|
||
步骤 2:验证绿色环境
|
||
curl http://127.0.0.1:8081/health
|
||
运行 9 项部署测试
|
||
|
||
步骤 3:切换流量
|
||
sed 修改 OpenResty proxy_pass → 127.0.0.1:8081
|
||
nginx -s reload
|
||
|
||
步骤 4:验证切换后
|
||
curl https://dev.xmclassmate.top/health
|
||
|
||
结果:绿色(:8081)=active 蓝色(:8080)=idle
|
||
下次部署时部署到蓝色
|
||
```
|
||
|
||
## 切换脚本
|
||
|
||
```bash
|
||
# 查看当前活动环境
|
||
./scripts/switch-env.sh --status
|
||
# → dev 环境: 蓝色 (127.0.0.1:8080)
|
||
|
||
# 切换到绿色
|
||
./scripts/switch-env.sh --env dev --switch green
|
||
# → 修改 proxy_pass 127.0.0.1:8081
|
||
# → nginx -s reload
|
||
# → 验证健康检查
|
||
```
|
||
|
||
## 数据库迁移注意事项
|
||
|
||
蓝绿部署中两个实例共享同一数据库(同一环境内的 milkydata 或 milkydata_dev),迁移脚本需要对**新旧两个版本的代码都兼容**:
|
||
|
||
| 迁移类型 | 兼容性 | 说明 |
|
||
|---------|--------|------|
|
||
| `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 dev --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` | `:8080` | `:8081` |
|
||
| 生产 | `xmclassmate.top` | `:4433` | `:4434` |
|
||
|
||
## 当前是否实施
|
||
|
||
当前项目规模(~100 日活),部署停机约 3-5 秒,实际影响可忽略。建议**保留文档**,当需要时再按 P1→P2 逐步实施。
|