蓝绿部署
维护蓝(当前)与绿(候选)两套等价环境,通过负载均衡或 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。
生成内容仅作检查项提醒;真实命令依赖云厂商 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 时长与长连接影响