Files
LabelChange-server/deployment/DEPLOYMENT_GUIDE.md
2026-06-01 16:30:29 +08:00

12 KiB
Raw Permalink Blame History

固定端口蓝绿部署完整指南

架构概述

本方案采用固定端口蓝绿部署策略,允许在不中断客户端访问的情况下更新应用程序:

网络流量 (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次失败后标记服务器为down
  • fail_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

问题3Nginx未切换流量

症状:切换后客户端仍连接到旧实例

排查步骤

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:

  1. 检查 instance_state.json确认 activeInstance 已变更
  2. 调用 /api/version 确认返回新版本号
  3. 检查部署日志最后一行应显示"蓝绿部署完成"

总结

这个固定端口蓝绿部署方案提供了:

  • 零停机部署:业务连续性有保障
  • 快速回滚:问题发生时可秒级回滚
  • 简单配置固定端口Nginx配置一次即可
  • 自动化PowerShell脚本全程自动化
  • 完整日志:所有操作都有详细日志记录

祝你部署顺利!🚀