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

## 架构概述

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

```
网络流量 (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. 创建必要的目录

```powershell
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`），按照以下方式配置：

```nginx
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
# 在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
# 在另一个PowerShell终端中
curl http://localhost:5000/api/health

# 应该返回：
# {
#   "status": "healthy",
#   "instance": "blue",
#   "port": 5000,
#   ...
# }
```

**步骤3**：初始化部署状态

```powershell
# 创建初始状态文件
$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）。

### 后续部署流程（核心部署脚本）

一旦初始化完成，所有后续部署都通过以下命令执行：

```powershell
# 执行蓝绿部署（自动选择非活跃实例）
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 | 旧实例关闭 | 新请求转发到新实例 ✓ |

---

## 环境变量

### 部署实例标识

启动应用时，需要设置环境变量标识实例：

```powershell
# 蓝实例
$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)**：
```json
{
  "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
```

**响应**：
```json
{
  "version": "1.0.0",
  "instance": "blue",
  "port": 5000,
  "buildTime": "2026-05-15T10:15:30Z",
  "timestamp": "2026-05-15T10:30:45Z"
}
```

---

## 回滚流程

### 发生故障时快速回滚

```powershell
# 执行回滚脚本
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
```

**内容示例**：
```json
{
  "activeInstance": "green",
  "lastUpdate": "2026-05-15 10:35:15",
  "version": "1.1.0"
}
```

---

## 故障排查

### 问题1：新实例健康检查失败

**症状**：部署中止，显示"新实例健康检查失败"

**排查步骤**：
```powershell
# 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：旧实例无法停止

**症状**：部署完成但旧实例仍在运行

**解决方案**：
```powershell
# 强制停止所有 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. **健康检查优化**
   ```powershell
   # 手动测试健康检查响应时间
   Measure-Command {
       curl http://localhost:5000/api/health
   }
   ```

### 5. **客户端重连机制**
   - 建议客户端实现自动重连
   - 设置合理的重试次数（3-5次）
   - 指数退避策略

---

## 快速参考命令

```powershell
# 查看当前活跃实例
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脚本全程自动化
- ✅ **完整日志**：所有操作都有详细日志记录

祝你部署顺利！🚀
