245 lines
6.5 KiB
Markdown
245 lines
6.5 KiB
Markdown
# 蓝绿部署(新服务器)
|
||
|
||
> **服务器**:47.109.203.92 (Aliyun, Debian 13)
|
||
> **nginx**:原生 nginx(非 Docker/OpenResty)
|
||
> **PostgreSQL**:Docker 容器 `postgres:17.6-alpine`
|
||
> **部署用户**:`deploy`(有 sudo 权限)
|
||
|
||
## 域名与环境映射
|
||
|
||
```
|
||
域名 环境 后端端口 数据库
|
||
────────────────────────────────────────────────────
|
||
dev.xmclassmate.top 开发/测试 :8080 milkydata_dev
|
||
xmclassmate.top 生产 :4433 / :4434 milkydata
|
||
```
|
||
|
||
> **原则**:两个域名永远指向各自的环境,不互换。生产采用蓝绿部署实现零停机。
|
||
|
||
## 当前问题
|
||
|
||
单实例部署时存在停机时间:
|
||
|
||
```
|
||
停止服务 → 上传新代码 → 重启服务 → 跑迁移
|
||
↑
|
||
3-5 秒停机
|
||
```
|
||
|
||
## 开发环境(dev.xmclassmate.top)
|
||
|
||
保持单实例,无需蓝绿:
|
||
|
||
```
|
||
dev.xmclassmate.top
|
||
│
|
||
nginx → :8080(单实例)
|
||
│
|
||
milkydata_dev
|
||
```
|
||
|
||
开发环境不需要蓝绿的原因:
|
||
|
||
| 原因 | 说明 |
|
||
|------|------|
|
||
| 停机时间可接受 | 仅开发者使用,重启 3-5 秒无影响 |
|
||
| 简化运维 | 少维护一套 systemd service |
|
||
| 快速迭代 | 直接 `deploy.sh development` 部署 |
|
||
|
||
## 生产环境(xmclassmate.top)— 蓝绿部署
|
||
|
||
### 架构
|
||
|
||
```
|
||
xmclassmate.top
|
||
│
|
||
nginx proxy(直接路由)
|
||
/ \
|
||
蓝色 :4433 绿色 :4434
|
||
(active) (idle)
|
||
\ /
|
||
milkydata(共享)
|
||
```
|
||
|
||
任何时候只有一个实例接收流量,另一个运行旧版本待命,切换零停机。
|
||
|
||
### 组件
|
||
|
||
**systemd service:**
|
||
|
||
```
|
||
/etc/systemd/system/
|
||
├── rust-backend-blue.service ← :4433
|
||
└── rust-backend-green.service ← :4434
|
||
```
|
||
|
||
两个 service 的 `DATABASE_URL` 都指向 `milkydata`,仅端口不同。
|
||
|
||
**nginx proxy 配置:**
|
||
|
||
```
|
||
# /www/sites/xmclassmate.top/proxy/root.conf
|
||
location ^~ / {
|
||
proxy_pass https://127.0.0.1:4433; # deploy.sh 切换此端口
|
||
}
|
||
```
|
||
|
||
> 生产环境使用 HTTPS proxy(`proxy_pass https://...`),因为后端自身处理 TLS。
|
||
|
||
切换时 `sed` 替换端口,`sudo nginx -s reload`。
|
||
|
||
### 部署流程
|
||
|
||
```
|
||
初始:蓝色(:4433)=active 绿色(:4434)=idle
|
||
|
||
步骤 1:部署到空闲环境(绿色)
|
||
① cargo build --release
|
||
② rsync 二进制 → 绿色目录
|
||
③ systemctl restart rust-backend-green.service
|
||
④ 运行数据库迁移
|
||
|
||
步骤 2:验证绿色环境
|
||
curl http://127.0.0.1:4434/health
|
||
run_tests
|
||
|
||
步骤 3:切换流量
|
||
sed 修改 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 --switch green
|
||
# 或切回蓝色
|
||
./scripts/switch-env.sh --switch blue
|
||
# 查看当前状态
|
||
./scripts/switch-env.sh --status
|
||
```
|
||
|
||
### 回滚
|
||
|
||
```bash
|
||
./scripts/switch-env.sh --env prod --switch blue # 即时恢复旧版本
|
||
```
|
||
旧环境代码未变,无需重新部署。
|
||
|
||
## 数据库
|
||
|
||
| 环境 | 数据库 | 说明 |
|
||
|------|--------|------|
|
||
| 开发 | `milkydata_dev` | 单实例直连 |
|
||
| 生产 | `milkydata` | 蓝绿实例共享,名称不变 |
|
||
|
||
> 生产库 `milkydata`,开发库 `milkydata_dev`,两者独立。
|
||
|
||
## 限制与注意事项
|
||
|
||
### 1. 部署只能部署到非活动端口
|
||
|
||
每次部署必须部署到**当前空闲的环境**,绝不能直接部署到正在接收流量的端口。
|
||
|
||
```
|
||
正确流程:
|
||
Green(:4434) 活动中 → 部署到 Blue(:4433) → 测试 → 切到 Blue(:4433)
|
||
Blue(:4433) 活动中 → 部署到 Green(:4434) → 测试 → 切到 Green(:4434)
|
||
|
||
错误:
|
||
Green(:4434) 活动中 → 直接部署到 Green(:4434) ← ❌ 会产生停机
|
||
```
|
||
|
||
**原因**:部署过程涉及服务重启(~3-5 秒),如果直接部署到活动中环境,
|
||
会导致在此期间的用户请求失败。
|
||
|
||
### 2. 代码只能通过 deploy.sh 部署
|
||
|
||
禁止手动 `rsync` + `systemctl restart` 部署。必须使用统一脚本:
|
||
|
||
```bash
|
||
# 正确
|
||
./deploy.sh production --target blue --yes
|
||
|
||
# 错误
|
||
cargo build --release && rsync ... systemctl restart ← ❌
|
||
```
|
||
|
||
**原因**:
|
||
- 自动备份旧版本,支持回滚
|
||
- 自动运行数据库迁移
|
||
- 自动验证服务健康
|
||
- 自动切换代理(零停机)
|
||
- 自动记录部署日志
|
||
- 跳过手动操作的遗漏风险
|
||
|
||
### 3. 部署后先验证再切换
|
||
|
||
`deploy.sh --skip-tests` 跳过了部署后的自动测试。建议仅在开发/快速迭代时使用,
|
||
生产环境应让测试跑完再切换。
|
||
|
||
### 4. 数据库兼容性(迁移注意事项)
|
||
|
||
蓝绿共享数据库,迁移需向前兼容:
|
||
|
||
| 迁移类型 | 兼容 | 说明 |
|
||
|---------|------|------|
|
||
| `CREATE TABLE` | ✅ | 新旧代码均可运行 |
|
||
| `ADD COLUMN` | ✅ | 需 `DEFAULT` 或允许 `NULL` |
|
||
| `RENAME COLUMN` | ❌ | 旧代码查询旧列名会失败 |
|
||
| `DROP COLUMN` | ❌ | 旧代码查询被删列会失败 |
|
||
|
||
不兼容的迁移需要三段式部署。
|
||
|
||
## 实施优先级
|
||
|
||
| 阶段 | 内容 | 工作量 |
|
||
|------|------|--------|
|
||
| P1 | 创建 blue + green 两个 systemd service | 小 |
|
||
| P2 | 编写 `deploy-blue-green.sh` + `switch-env.sh` | 中 |
|
||
| P3 | 实现 OpenResty proxy 配置切换 | 中 |
|
||
| P4 | 改造 `deploy.sh` 支持 `--blue-green` | 中 |
|
||
| P5 | 不兼容迁移的三段式部署文档 | 小 |
|
||
| P6 | 回滚文档 | 小 |
|
||
|
||
## 生产上线待办
|
||
|
||
| # | 步骤 | 说明 | 状态 |
|
||
|---|------|------|------|
|
||
| 1 | 数据迁移 | 已完成 | ✅ |
|
||
| 2 | 准备生产 service 文件 | 已完成 | ✅ |
|
||
| 3 | 部署新代码到 `:4433` 和 `:4434` | 已完成 | ✅ |
|
||
| 4 | `env.ts` 设 `CURRENT_ENV = 'production'` | 已完成 | ✅ |
|
||
| 5 | 微信开发者工具上传小程序 | 已完成 | ✅ |
|
||
| 6 | 确认 nginx `proxy_pass` 指向 :4433 | 已完成 | ✅ |
|
||
|
||
## 实施状态
|
||
|
||
蓝绿部署已实施并运行中:
|
||
|
||
| 组件 | 状态 |
|
||
|------|------|
|
||
| Blue service (:4433) | ✅ 运行中,当前活跃 |
|
||
| Green service (:4434) | ✅ 运行中,待命中 |
|
||
| `deploy.sh production --target blue/green` | ✅ 已支持 |
|
||
| `switch-env.sh --switch blue/green` | ✅ 自动切换 nginx proxy |
|
||
| nginx proxy | ✅ 指向活动中环境 |
|
||
|
||
### 下次部署流程
|
||
|
||
```bash
|
||
# 1. 查看当前活动中环境
|
||
./scripts/switch-env.sh --status
|
||
|
||
# 2. 部署到空闲环境(假设 green 活动中 → 部署到 blue)
|
||
./deploy.sh production --target blue --yes
|
||
|
||
# 3. 部署完成后自动切换流量到 blue
|
||
# deploy.sh 自动调用 switch-env.sh --switch blue
|
||
```
|