蓝绿部署

维护蓝(当前)与绿(候选)两套等价环境,通过负载均衡或 DNS 一键切流;适合 Agent 输出检查清单与 schema 向前兼容注意事项。

SKILL 须覆盖:绿环境部署新版本、健康检查与冒烟、切换流量、观察窗口内监控指标,以及发现问题时切回蓝环境并保留绿环境用于诊断。

数据库与缓存变更常是瓶颈:需说明 expand-contract 模式、迁移是否在切流前完成、双写或只读副本策略,避免蓝绿同时写 incompatible schema。

蓝绿主流程(skill-flow-block)

  [ 蓝:线上流量 │ 绿:候选版本 ]
        │
        ▼
  ┌─────────────┐     镜像 / 配置 / 密钥与蓝对齐;就绪探针通过
  │ 绿环境部署    │
  └─────────────┘
        │
        ▼
  ┌─────────────┐     冒烟、契约测试、只读影子流量(可选)
  │ 验证与兼容    │──── DB:迁移顺序、双写窗口、只读副本
  └─────────────┘
        │
        ▼
  ┌─────────────┐     LB 权重 / DNS TTL / 网关路由;先 drain 再抬权重
  │  切流 Switch  │──── 有状态:粘性、WebSocket、长轮询单独策略
  └─────────────┘
        │
        ▼
  ┌─────────────┐     错误率、P99、业务探针;未达标 → 回切蓝
  │ 观察窗口     │──── 绿保留:日志与复现,不立即销毁
  └─────────────┘

Runbook 中每一步须可单击或一条命令执行;回切指定负责人与审批条件,避免「口头切回」无审计。

切流(Switch)

切流是「把入口流量从蓝指到绿」的原子或渐进动作:常见实现为负载均衡目标组切换、API 网关路由版本、或 DNS 记录变更(注意 TTL 与客户端缓存)。

  • 即时切换:适合无状态 HTTP;配合健康检查与自动摘除坏实例。
  • 渐进切换:按权重或地域分批,观察指标后再加到 100%,降低爆炸半径。
  • 切换前确认配置与密钥在两套环境中一致且版本匹配;定义「成功切换」的量化标准(错误率、P99、业务探针)。
# AWS ALB 蓝绿流量切换(AWS CLI 示例)

# 1. 查看当前目标组权重
aws elbv2 describe-rules \
  --listener-arn arn:aws:elasticloadbalancing:us-east-1:123456789:listener/... \
  --query 'Rules[?Priority==`1`].Actions'

# 2. 将 10% 流量切到绿色目标组(渐进切换)
aws elbv2 modify-rule \
  --rule-arn arn:aws:elasticloadbalancing:us-east-1:...:rule/... \
  --actions '[
    {"Type":"forward","ForwardConfig":{"TargetGroups":[
      {"TargetGroupArn":"arn:...blue-tg","Weight":90},
      {"TargetGroupArn":"arn:...green-tg","Weight":10}
    ]}}
  ]'

# 3. 观察 5 分钟后全量切换(蓝=0,绿=100)
aws elbv2 modify-rule \
  --rule-arn arn:aws:elasticloadbalancing:us-east-1:...:rule/... \
  --actions '[
    {"Type":"forward","ForwardConfig":{"TargetGroups":[
      {"TargetGroupArn":"arn:...blue-tg","Weight":0},
      {"TargetGroupArn":"arn:...green-tg","Weight":100}
    ]}}
  ]'

# 4. 回切(发现问题时执行:蓝=100,绿=0)
# 修改 Weight 值并重新运行 modify-rule 即可

排空(Drain)与有状态

排空:在从负载均衡摘掉实例或缩容前,停止接受新连接并让已有请求与长连接在限时内自然结束,避免切换瞬间大量 502 或事务中断。

  • HTTP:配合 Connection: close、就绪探针失败、graceful shutdown 超时。
  • WebSocket / 长连接:需协议层迁移策略、服务端广播重连、或粘性会话仍落在旧色直到 drain 完成。
  • 会话粘性:切换后新会话应落在绿色;旧会话在 drain 窗口内仍可由蓝色服务,Runbook 写明最长等待与强制断开条件。
# Nginx upstream 蓝绿切换配置示例
# /etc/nginx/conf.d/upstream.conf

upstream app_backend {
    # 蓝绿切换:修改注释行并执行 nginx -s reload
    server blue.internal:8080;   # 蓝(当前线上)
    # server green.internal:8080;  # 绿(新版本,切换时取消注释并注释蓝)

    keepalive 64;
}

server {
    listen 443 ssl;
    server_name api.example.com;

    # 排空配置:蓝色实例 drain 期间标记 down
    # upstream app_backend { server blue.internal:8080 down; server green.internal:8080; }

    location / {
        proxy_pass         http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header   Connection "";
        proxy_read_timeout 120s;  # drain 超时:允许 120s 内完成进行中请求
    }
}
# 无中断热加载:sudo nginx -t && sudo nginx -s reload

数据与 schema 兼容

采用 expand-contract:先加列/加表(向后兼容)→ 双版本代码共存 → 数据回填 → 再删旧列。迁移若在切流后执行,须保证蓝绿任一读写的 schema 互相兼容。

  • 缓存:键空间版本前缀、TTL 与惊群;避免两色对同一 key 语义不一致。
  • 消息队列:消费者版本与重试死信策略;破坏性 schema 变更需双消费或隔离 topic。
-- 数据库 Expand-Contract 迁移模式(以 PostgreSQL 为例)

-- 阶段 1:Expand — 新增列(向后兼容,蓝绿均可读写)
ALTER TABLE users ADD COLUMN phone_normalized VARCHAR(20);
CREATE INDEX CONCURRENTLY idx_users_phone_normalized ON users(phone_normalized);
-- 此时蓝(旧代码)忽略新列,绿(新代码)写入新列

-- 阶段 2:数据回填(切流后绿色运行期间执行)
UPDATE users
SET phone_normalized = normalize_phone(phone)
WHERE phone_normalized IS NULL
  AND phone IS NOT NULL;

-- 阶段 3:验证回填完整性
SELECT COUNT(*) FROM users WHERE phone IS NOT NULL AND phone_normalized IS NULL;
-- 结果应为 0 再进入下一阶段

-- 阶段 4:Contract — 移除旧列(下次发布,绿已全量后)
-- ALTER TABLE users DROP COLUMN phone;  -- 危险:需确认蓝已完全退出

观察、成功标准与回切

  • 观察窗口内对比蓝绿两侧或切换前后的 SLO 指标;业务探针(下单、登录等)优先于纯 HTTP 200。
  • 回切须在 Runbook 中可一键执行,并保留绿色环境用于对比配置与日志。
  • 切换后复盘:记录实际 drain 时长、是否误杀长连接、数据库锁与迁移是否影响切流。
#!/bin/bash
# Smoke Test 脚本:切流后验证绿色环境核心路径
set -euo pipefail
BASE="https://api.example.com"

echo "=== Smoke Test: 切流后核心功能验证 ==="

# 1. 版本号验证(确认流量已到新版本)
version=$(curl -sf "$BASE/api/version" | jq -r '.version')
[[ "$version" == "v1.4.2" ]] && echo "  OK  版本=$version" \
  || { echo "FAIL 期望 v1.4.2,实际 $version" >&2; exit 1; }

# 2. 登录流程
token=$(curl -sf -X POST "$BASE/auth/token" \
  -H 'Content-Type: application/json' \
  -d '{"username":"smoke-test@example.com","password":"'$SMOKE_TEST_PASS'"}' \
  | jq -r '.access_token')
[[ -n "$token" ]] && echo "  OK  登录获取 token" || { echo "FAIL 登录失败" >&2; exit 1; }

# 3. 核心业务接口
curl -sf "$BASE/api/v1/products?limit=5" \
  -H "Authorization: Bearer $token" | jq -e '.items | length > 0' \
  && echo "  OK  商品列表接口" || { echo "FAIL 商品接口异常" >&2; exit 1; }

# 4. 错误率检查(Prometheus)
err_rate=$(curl -sf "http://prometheus:9090/api/v1/query?query=\
rate(http_requests_total{status=~\"5..\"}[5m])/rate(http_requests_total[5m])" \
  | jq -r '.data.result[0].value[1]')
echo "  当前 5xx 错误率: $err_rate(阈值 0.01)"

echo "=== Smoke Test 通过 ✓ ==="

切流备忘生成器

选择切流面与策略,生成可贴进 Runbook 的「切流备忘」(非可执行脚本);按实际栈替换控制台/API 名称与资源 ID。

流量入口(Switch 面)
切换形态
排空(Drain)与长连接

生成内容仅作检查项提醒;真实命令依赖云厂商 CLI/控制台。DNS 切换需叠加客户端与 CDN 缓存;网关金丝雀需确认指标来源与回滚路由优先级。

---
name: blue-green-deploy
description: 蓝绿双环境切流、Smoke Test 与数据兼容策略
version: 2.0
---
# 绿环境部署
- 镜像版本、配置、密钥与蓝对齐
- kubectl rollout status deployment/myapp-green -n production
- 就绪探针全绿:curl -sf https://green.internal/healthz/ready

# 数据库迁移(切流前)
- Expand:ALTER TABLE 新增列(向后兼容)
- 验证蓝绿均可读写新 schema
- 回填数据:UPDATE ... WHERE new_col IS NULL

# 切流(Switch)
- AWS ALB:modify-rule 将 green-tg weight 从 0→10→100
- Nginx:修改 upstream weight 后 nginx -s reload
- DNS:降低 TTL 至 60s 后再切换 A 记录

# 验证(Smoke Test)
- 版本号确认:curl $BASE/api/version | jq .version
- 业务流程:登录→查询→下单抽样
- 错误率 < 0.5%,P99 < 800ms,观察 15 min

# 回切(Rollback)
- ALB weight 蓝=100 绿=0(或 Nginx upstream 切回)
- 保留绿色环境用于 diff 日志与配置排查
- 记录实际 drain 时长与长连接影响

返回技能库 更多技能入口