12 KiB
12 KiB
固定端口蓝绿部署完整指南
架构概述
本方案采用固定端口蓝绿部署策略,允许在不中断客户端访问的情况下更新应用程序:
网络流量 (Nginx)
↓
→ 当前活跃实例 (蓝/绿) [端口固定: 5000 或 5001]
↓
应用程序处理
关键特点
- 蓝实例:固定运行在 端口 5000
- 绿实例:固定运行在 端口 5001
- 零停机:Nginx始终指向活跃实例,切换时无中断
- 快速回滚:备份机制允许快速恢复
部署前准备
1. 目录结构创建
确保以下目录结构存在:
D:\EPproject\LabelReplaceServer\
├── deployment/
│ ├── blue/ # 蓝实例应用目录
│ ├── green/ # 绿实例应用目录
│ ├── backups/ # 备份目录
│ ├── logs/ # 部署日志目录
│ ├── scripts/ # 部署脚本目录
│ │ ├── build-and-publish.ps1
│ │ ├── health-check.ps1
│ │ ├── deploy-blue-green.ps1
│ │ ├── stop-instance.ps1
│ │ └── rollback.ps1
│ └── config/
│ └── deployment-config.json
├── src/
├── publish/
└── ...
2. 创建必要的目录
mkdir D:\EPproject\LabelReplaceServer\deployment\blue
mkdir D:\EPproject\LabelReplaceServer\deployment\green
mkdir D:\EPproject\LabelReplaceServer\deployment\backups
mkdir D:\EPproject\LabelReplaceServer\deployment\logs
mkdir D:\EPproject\LabelReplaceServer\deployment\scripts
mkdir D:\EPproject\LabelReplaceServer\deployment\config
3. 配置Nginx反向代理
在你的Nginx配置文件中(通常是 nginx.conf),按照以下方式配置:
upstream backend {
# 蓝绿实例,一个为主,一个为备用
server 127.0.0.1:5000 max_fails=2 fail_timeout=10s;
server 127.0.0.1:5001 backup;
}
server {
listen 80;
server_name your-domain.com;
location / {
proxy_pass http://backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 重要:设置连接超时
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
location /api/health {
proxy_pass http://backend;
access_log off;
}
}
关键配置说明:
max_fails=2:在2次失败后标记服务器为downfail_timeout=10s:故障超时10秒backup:指定备用服务器,平时不接收流量
部署流程
第一次初始化部署
步骤1:手动启动蓝实例
# 在PowerShell中执行以下命令
# 编译发布到blue目录
D:\EPproject\LabelReplaceServer\deployment\scripts\build-and-publish.ps1 `
-OutputDirectory "D:\EPproject\LabelReplaceServer\deployment\blue" `
-Version "1.0.0"
# 手动启动蓝实例
cd D:\EPproject\LabelReplaceServer\deployment\blue
$env:DEPLOYMENT_INSTANCE = "blue"
$env:SHUTDOWN_TIMEOUT = "30"
.\CONTROLLER.exe
步骤2:验证蓝实例运行
# 在另一个PowerShell终端中
curl http://localhost:5000/api/health
# 应该返回:
# {
# "status": "healthy",
# "instance": "blue",
# "port": 5000,
# ...
# }
步骤3:初始化部署状态
# 创建初始状态文件
$state = @{
activeInstance = "blue"
lastUpdate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
version = "1.0.0"
}
$state | ConvertTo-Json |
Set-Content -Path "D:\EPproject\LabelReplaceServer\deployment\instance_state.json" -Force
步骤4:更新Nginx配置
修改Nginx配置,让主服务器指向蓝实例(5000),备用指向绿实例(5001)。
后续部署流程(核心部署脚本)
一旦初始化完成,所有后续部署都通过以下命令执行:
# 执行蓝绿部署(自动选择非活跃实例)
D:\EPproject\LabelReplaceServer\deployment\scripts\deploy-blue-green.ps1 `
-Version "1.1.0"
# 或指定目标实例
D:\EPproject\LabelReplaceServer\deployment\scripts\deploy-blue-green.ps1 `
-Version "1.1.0" `
-TargetInstance "green"
部署脚本执行流程:
1. 确定当前活跃实例(读取 instance_state.json)
├─ 若为 blue → 部署到 green
├─ 若为 green → 部署到 blue
2. 编译新版本到非活跃实例
├─ 执行 dotnet clean/restore/build/publish
├─ 保存当前版本为备份
3. 启动新实例
├─ 设置环境变量 DEPLOYMENT_INSTANCE=green/blue
├─ 启动 CONTROLLER.exe
4. 健康检查(最多30次重试,每次间隔1秒)
├─ 调用 /api/health 端点
├─ 若成功 → 继续
├─ 若失败 → 回滚并退出
5. 切换流量(更新Nginx配置或DNS)
├─ 更新 instance_state.json
├─ Nginx自动切换到新实例
6. 优雅关闭旧实例
├─ 等待旧实例完成当前请求(最多30秒)
├─ 停止旧实例进程
7. 记录日志
├─ 保存到 deployment/logs/deployment.log
部署中发生了什么?
| 时间 | 操作 | 客户端体验 |
|---|---|---|
| T=0s | 新实例启动中 | 请求转发到蓝/绿 ✓ |
| T=2s | 健康检查中 | 请求转发到蓝/绿 ✓ |
| T=5s | 状态更新 | 可能短暂延迟(<1s) |
| T=7s | 旧实例关闭 | 新请求转发到新实例 ✓ |
环境变量
部署实例标识
启动应用时,需要设置环境变量标识实例:
# 蓝实例
$env:DEPLOYMENT_INSTANCE = "blue"
$env:SHUTDOWN_TIMEOUT = "30"
.\CONTROLLER.exe
# 或
# 绿实例
$env:DEPLOYMENT_INSTANCE = "green"
$env:SHUTDOWN_TIMEOUT = "30"
.\CONTROLLER.exe
环境变量说明
| 变量名 | 说明 | 默认值 | 用途 |
|---|---|---|---|
DEPLOYMENT_INSTANCE |
实例标识 | "blue" | 决定使用的端口(blue=5000, green=5001) |
SHUTDOWN_TIMEOUT |
优雅关闭超时 | "30" | 秒数,等待现有请求完成的最长时间 |
ASPNETCORE_ENVIRONMENT |
环境 | "Production" | ASP.NET Core 环境配置 |
健康检查端点
/api/health 端点
请求:
GET /api/health
响应 (200 OK):
{
"status": "healthy",
"instance": "blue",
"port": 5000,
"timestamp": "2026-05-15T10:30:45Z",
"uptime": "2026-05-15T10:15:30Z",
"environment": "Production"
}
/api/version 端点
请求:
GET /api/version
响应:
{
"version": "1.0.0",
"instance": "blue",
"port": 5000,
"buildTime": "2026-05-15T10:15:30Z",
"timestamp": "2026-05-15T10:30:45Z"
}
回滚流程
发生故障时快速回滚
# 执行回滚脚本
D:\EPproject\LabelReplaceServer\deployment\scripts\rollback.ps1
回滚流程:
1. 读取当前活跃实例
2. 停止当前实例
3. 从最新备份恢复文件
4. 启动恢复的实例
5. 健康检查验证
6. 更新状态文件
7. Nginx自动切换回旧端口
预期结果:
前状态:green (新版本) 活跃
回滚后:blue (旧版本) 活跃
客户端流量自动转向 blue(端口 5000)
监控和日志
日志位置
所有部署日志记录在:
D:\EPproject\LabelReplaceServer\deployment\logs\deployment.log
日志内容示例
[2026-05-15 10:30:45] [INFO] [BluGreen] ========================================
[2026-05-15 10:30:45] [INFO] [BluGreen] 蓝绿部署流程开始
[2026-05-15 10:30:45] [INFO] [BluGreen] 版本: 1.1.0
[2026-05-15 10:30:45] [INFO] [BluGreen] 已加载部署配置
[2026-05-15 10:30:45] [INFO] [BluGreen] 当前活跃实例: blue
[2026-05-15 10:30:45] [INFO] [BluGreen] 下一个部署实例: green
[2026-05-15 10:35:12] [INFO] [BluGreen] 健康检查通过
[2026-05-15 10:35:13] [INFO] [BluGreen] 已更新活跃实例为: green (版本: 1.1.0)
[2026-05-15 10:35:15] [INFO] [BluGreen] 蓝绿部署完成!
实例状态文件
D:\EPproject\LabelReplaceServer\deployment\instance_state.json
内容示例:
{
"activeInstance": "green",
"lastUpdate": "2026-05-15 10:35:15",
"version": "1.1.0"
}
故障排查
问题1:新实例健康检查失败
症状:部署中止,显示"新实例健康检查失败"
排查步骤:
# 1. 检查应用是否启动
Get-Process CONTROLLER
# 2. 手动测试健康检查
curl http://localhost:5000/api/health
curl http://localhost:5001/api/health
# 3. 查看部署日志
Get-Content "D:\EPproject\LabelReplaceServer\deployment\logs\deployment.log" -Tail 50
# 4. 检查应用日志
Get-Content "D:\EPproject\LabelReplaceServer\deployment\logs\api_log-*.txt" -Tail 50
问题2:旧实例无法停止
症状:部署完成但旧实例仍在运行
解决方案:
# 强制停止所有 CONTROLLER 进程
Get-Process CONTROLLER | Stop-Process -Force
# 等待2秒后验证
Start-Sleep -Seconds 2
Get-Process CONTROLLER -ErrorAction SilentlyContinue
问题3:Nginx未切换流量
症状:切换后客户端仍连接到旧实例
排查步骤:
1. 确认 instance_state.json 已更新
- 检查 activeInstance 字段是否变更
2. 检查 Nginx 配置
- 确保上游地址正确
- 重新加载 Nginx: nginx -s reload
3. 清除DNS缓存(如适用)
- ipconfig /flushdns
4. 检查客户端连接
- 新连接应转向新实例
- 已建立连接可能保持不变
最佳实践
1. 选择合适的部署时间
- 避免业务高峰期
- 选择流量较少的时间窗口
- 建议凌晨或夜间部署
2. 监控部署过程
- 打开日志文件实时查看
- 监控两个端口的流量
- 部署后进行功能验证
3. 备份管理
- 定期清理旧备份(保留最近5个版本)
- 备份目录空间充足
- 测试备份可恢复性
4. 健康检查优化
# 手动测试健康检查响应时间
Measure-Command {
curl http://localhost:5000/api/health
}
5. 客户端重连机制
- 建议客户端实现自动重连
- 设置合理的重试次数(3-5次)
- 指数退避策略
快速参考命令
# 查看当前活跃实例
Get-Content "D:\EPproject\LabelReplaceServer\deployment\instance_state.json" | ConvertFrom-Json
# 查看部署日志(最近50行)
Get-Content "D:\EPproject\LabelReplaceServer\deployment\logs\deployment.log" -Tail 50
# 测试蓝实例
curl http://localhost:5000/api/health
# 测试绿实例
curl http://localhost:5001/api/health
# 查看CONTROLLER进程
Get-Process CONTROLLER
# 部署新版本
& "D:\EPproject\LabelReplaceServer\deployment\scripts\deploy-blue-green.ps1" -Version "1.2.0"
# 回滚到上一个版本
& "D:\EPproject\LabelReplaceServer\deployment\scripts\rollback.ps1"
# 停止应用
Get-Process CONTROLLER | Stop-Process -Force
常见问题 (FAQ)
Q: 为什么要用固定端口而不是动态端口? A: 固定端口更简单且不需要Nginx权限更改,部署脚本也更简洁。Nginx配置一次后无需修改。
Q: 部署期间客户端会断线吗? A: 新连接会自动转向新实例。已建立的长连接会保持到旧实例,直到超时或主动关闭。
Q: 回滚需要多长时间? A: 通常2-5分钟,取决于实例启动时间和健康检查通过速度。
Q: 可以同时运行两个实例吗? A: 可以,但同一时间只有一个实例作为"活跃实例"接收流量。另一个是备用。
Q: 如何验证部署成功? A:
- 检查 instance_state.json,确认 activeInstance 已变更
- 调用 /api/version 确认返回新版本号
- 检查部署日志最后一行应显示"蓝绿部署完成"
总结
这个固定端口蓝绿部署方案提供了:
- ✅ 零停机部署:业务连续性有保障
- ✅ 快速回滚:问题发生时可秒级回滚
- ✅ 简单配置:固定端口,Nginx配置一次即可
- ✅ 自动化:PowerShell脚本全程自动化
- ✅ 完整日志:所有操作都有详细日志记录
祝你部署顺利!🚀