6.5 KiB
6.5 KiB
蓝绿部署(新服务器)
服务器: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
下次部署到蓝色
切换脚本
./scripts/switch-env.sh --switch green
# 或切回蓝色
./scripts/switch-env.sh --switch blue
# 查看当前状态
./scripts/switch-env.sh --status
回滚
./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 部署。必须使用统一脚本:
# 正确
./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 | ✅ 指向活动中环境 |
下次部署流程
# 1. 查看当前活动中环境
./scripts/switch-env.sh --status
# 2. 部署到空闲环境(假设 green 活动中 → 部署到 blue)
./deploy.sh production --target blue --yes
# 3. 部署完成后自动切换流量到 blue
# deploy.sh 自动调用 switch-env.sh --switch blue