跳转到内容

发布与回滚规范

灰度发布、回滚机制、零停机部署、发布审批


[Standard] 根据变更类型和风险等级选择发布模式:

发布模式适用场景风险回滚速度
蓝绿部署全量切换、重大版本低秒级
滚动发布常规迭代中分钟级
灰度发布(金丝雀)高风险变更、新功能低秒级
A/B 测试产品验证、UI 改动低秒级

[Default] 核心服务每周至少发布 1 次,禁止长期积压变更后一次性大版本发布。小步快跑,降低单次变更风险。

[Caution] 禁止在以下时段发布:

  • 法定节假日前 1 天及节假日期间
  • 周五下午 18:00 之后
  • 业务高峰期(如电商大促期间)

[Standard] 生产环境发布窗口:工作日 10:00-16:00,确保有充足的运维和研发人力值守。


[Standard] 灰度发布按以下比例逐步放量,每个阶段观察至少 15 分钟,无异常再进入下一阶段。

1% → 5% → 10% → 30% → 50% → 100%
阶段流量比例观察重点观察时长
金丝雀1%错误率、核心接口响应时间15 分钟
小流量5%错误率、资源使用率15 分钟
中流量10%业务指标、依赖服务健康15 分钟
大流量30%全量监控指标15 分钟
半量50%与全量对比15 分钟
全量100%持续观察 30 分钟30 分钟

[Standard] 灰度流量可按以下维度切分,根据业务场景选择:

维度说明示例
按用户 ID特定用户群体用户 ID 尾数为 0 的用户
按地域特定地区北京、上海地区
按设备特定终端iOS 16+ 设备
按请求头自定义标识X-Gray: true
按比例随机百分比10% 流量

Nginx 灰度示例(按请求头):

upstream backend_v1 { server 10.0.0.1:8080; }
upstream backend_v2 { server 10.0.0.2:8080; }
 
server {
    location / {
        if ($http_x_gray = "true") {
            proxy_pass http://backend_v2;
        }
        proxy_pass http://backend_v1;
    }
}

K8s 金丝雀发布示例:

# 新版本 Deployment(金丝雀),仅 1 个副本
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service-v2
spec:
  replicas: 1
  selector:
    matchLabels:
      app: user-service
      version: v2
  template:
    metadata:
      labels:
        app: user-service
        version: v2
    spec:
      containers:
        - name: user-service
          image: registry.example.com/user-service:2.0.0
---
# Service 同时匹配 v1 和 v2,按副本数分配流量
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - port: 80

[Requirement] 灰度过程中出现以下任一情况,立即中止并回滚:

  • 错误率 ≥ 1%(或高于基线 0.5 个百分点)
  • 核心接口 P99 响应时间劣化 ≥ 50%
  • 业务核心指标(下单量、支付成功率等)下降 ≥ 5%
  • 出现 P0/P1 级故障

[Requirement] 每个版本发布前必须制定回滚方案,回滚操作必须在 5 分钟内完成。

[Caution] 回滚优先于定位问题。先回滚恢复服务,再排查根因。

回滚方式适用场景操作耗时
流量切回蓝绿/灰度发布将流量切回旧版本秒级
镜像回滚滚动发布重新部署上一版本镜像分钟级
配置回滚配置变更恢复上一版本配置秒级
数据回滚数据变更执行回滚 SQL / 恢复备份分钟~小时级

[Requirement] 发布前必须在发布单中明确回滚步骤,运维人员可独立执行。

发布单模板:

发布版本:v2.3.1
发布人:张三
发布时间:2024-01-15 14:00
变更内容:新增订单导出功能
回滚步骤:
1. K8s 回滚 Deployment:kubectl rollout undo deployment/user-service
2. 验证旧版本健康:curl http://user-service/health
3. 确认核心接口正常
回滚耗时:约 3 分钟

[Standard] 核心服务配置自动回滚策略,当监控指标异常时自动触发回滚。

# K8s 滚动发布配置
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  minReadySeconds: 30          # 新 Pod 就绪后至少等 30 秒
  progressDeadlineSeconds: 300 # 5 分钟内未完成则视为失败
  • ❌ 发布后发现问题,先尝试修复再决定是否回滚,导致故障扩大。
  • ❌ 没有回滚预案,出问题时临时想方案。
  • ❌ 回滚依赖数据库结构变更,无法快速回滚。

[Requirement] 所有服务必须实现健康检查端点(/health),部署平台通过健康检查判断新实例是否就绪。

# FastAPI 健康检查示例
@app.get("/health")
async def health():
    # 检查数据库、缓存等依赖
    db_ok = await check_db()
    redis_ok = await check_redis()
    if db_ok and redis_ok:
        return {"status": "ok"}
    raise HTTPException(status_code=503, detail="unhealthy")

[Requirement] 服务必须支持优雅停机:收到终止信号后,停止接收新请求,处理完在途请求后再退出。

# FastAPI 优雅停机
import signal
import asyncio
 
@app.on_event("shutdown")
async def shutdown():
    # 等待在途请求完成(最长 30 秒)
    await asyncio.sleep(30)
    # 关闭资源
    await db.close()

[Standard] 优雅停机等待时间不超过 30 秒,超时后强制终止。

[Standard] 滚动部署时,每次只更新部分实例,确保服务始终可用。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 10
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 2          # 最多多出 2 个 Pod
      maxUnavailable: 0    # 不允许不可用 Pod(保证零停机)

[Standard] 部署前从负载均衡摘除旧实例,等待在途请求完成后再销毁。

1. 启动新版本 Pod
2. 等待健康检查通过
3. 新版本 Pod 加入负载均衡
4. 旧实例标记为不可用,停止接收新请求
5. 等待旧实例在途请求处理完成(≤30s)
6. 销毁旧实例
7. 重复直到所有实例更新完成

[Caution] 数据库结构变更必须向后兼容,确保新旧版本代码可同时运行。

变更类型兼容做法不兼容做法
加字段允许 NULL 或有默认值加 NOT NULL 无默认值字段
删字段先发布不使用该字段的代码,再删字段直接删字段
改字段名加新字段,双写,再删旧字段直接 rename
改字段类型加新字段,迁移数据,再删旧字段直接 alter

[Requirement] 生产环境发布必须经过审批,流程如下:

提交发布单 → 技术负责人审批 → 运维审批 → 执行发布

[Requirement] 发布单必须包含以下信息:

字段说明
版本号语义化版本号
变更内容简要描述本次变更
变更范围影响的服务、模块
风险评估风险等级(低/中/高)
发布时间计划发布时间
回滚方案详细回滚步骤
验证方案发布后如何验证
变更类型审批人
前端静态资源前端负责人
后端服务(低风险)后端负责人
后端服务(高风险)后端负责人 + 运维负责人
数据库结构变更DBA + 后端负责人
基础设施变更运维负责人
紧急热修复值班负责人(事后补审批)

[Requirement] 发布完成后,必须执行以下验证:

  1. 健康检查:所有实例 /health 返回 200
  2. 冒烟测试:核心接口(登录、下单、支付)正常
  3. 监控指标:错误率、响应时间、资源使用率在正常范围
  4. 业务指标:核心业务指标无异常波动

[Standard] 发布后持续观察 30 分钟,无异常视为发布成功。

[Requirement] 每次发布必须记录发布日志,包括:发布人、发布时间、版本、变更内容、是否成功、回滚情况。保留至少 1 年。

  • ❌ 发布单只有版本号,没有变更内容和回滚方案。
  • ❌ 发布后不做验证,直接离开。
  • ❌ 紧急热修复不走审批流程,事后也不补记录。
  • ❌ 周五下午发布,出问题无人处理。