2. 动态交付概念:蓝绿部署、金丝雀发布、滚动更新
2.1 动态交付到底在解决什么问题?
你想想看,一个应用上线,最怕什么?
我最怕新版本推上去,用户直接报错,然后一群人围过来问「怎么回事」。传统的停机更新,说白了就是拿业务连续性赌一把。赌赢了没人夸你,赌输了背锅的就是你。
动态交付要解决的,本质上就两件事:降低风险 和 提升效率。让新版本先在小范围验证,确认没问题再全量推,出问题能秒级回滚。这不是什么花架子,是生产环境活下去的必备能力。
下面三种策略,是业界公认的三种主流玩法。我在不同项目里都用过,各有各的脾气,咱们一个一个说。
2.2 蓝绿部署:简单粗暴,但好用
蓝绿部署的思路,说白了就是准备两套一模一样的环境——一套叫蓝,一套叫绿。任何时候只有一套在对外服务,另一套闲着。
你要发新版,就把新版部署到空闲的那套上,然后做个全量切换。比如之前是蓝环境在线,你把绿环境部署好新版本,测一下没问题,把流量切到绿环境。如果出事了,再切回蓝环境,回滚就是秒级的事。
我在一个金融项目里用过这个模式。当时是核心交易系统,停机一秒都是大事。我们搭了两套完全独立的环境,数据库也做了双写。切换的时候,我盯着监控屏,心跳都加快了。好在一切顺利,从切流量到确认稳定,前后不到30秒。
蓝绿部署的优缺点很明显:
- 优点: 切换极快、回滚极快、流程简单、运维压力小。
- 缺点: 资源成本翻倍,等于你得养着一套几乎不产生价值的空闲环境。
- 适用场景: 核心业务、对停机零容忍的系统、团队规模不大的中小项目。
下面是一个简化版的蓝绿切换 Service 配置示意:
# 蓝色环境 Service(当前在线)
apiVersion: v1
kind: Service
metadata:
name: my-app
spec:
selector:
app: my-app
version: blue # 指向蓝色环境
ports:
- port: 80
targetPort: 8080
# 需要切换时,只需将 version 改为 green
# 然后 apply 即可,kube-proxy 会立即更新转发规则
2.3 金丝雀发布:先派一只鸟探路
金丝雀发布的名字来自煤矿里的金丝雀——先放一只鸟进去,如果鸟没事,人才进去。这个比喻很形象,说白了就是先让一小部分用户用新版本,观察一会儿没问题,再逐步放大流量比例。
我曾在一次电商大促前做金丝雀发布。当时只放了5%的流量到新版本,结果监控发现新版本的内存泄漏——虽然不致命,但跑24小时肯定出事。幸好只放了5%,回滚影响面极小。要是直接全量推,那天晚上就别想睡了。
金丝雀发布的核心在于:用真实流量做验证。测试环境永远无法模拟生产环境的所有情况,尤其是并发量、数据分布、第三方依赖的异常行为。
金丝雀发布的典型流程:
- 部署新版本,只分配 1%-5% 的流量。
- 持续监控错误率、延迟、业务指标(如订单量、支付成功率)。
- 观察期从几分钟到几小时不等,视业务重要程度而定。
- 确认稳定后,逐步扩大到 10%、30%、50%、100%。
- 如果任何一步出现异常,立即将流量切回旧版本。
它的优缺点也很清晰:
- 优点: 风险极低、真实流量验证、适合大规模系统。
- 缺点: 发布周期较长、对监控体系要求高、需要精细的流量控制能力。
- 适用场景: 用户量大的互联网服务、微服务架构、对稳定性极其敏感的系统。
2.4 滚动更新:温吞水,但实在
滚动更新是Kubernetes默认的更新策略。它的做法是:一次替换一部分旧实例,逐步全部换成新版本。整个过程没有独立的环境,就是在现有集群里"温水煮青蛙"式地替换。
我记得有一年在做容器化迁移,整个集群有200多个节点。我用滚动更新推送新版本,一次替换20%的实例。过程平稳得让我有点不习惯——没有告警,没有报错,业务完全无感知。
maxSurge(允许超出期望副本数的最大实例数)和 maxUnavailable(允许不可用的最大实例数)。这两个参数决定了更新的速度和安全性。
但滚动更新也有它的软肋。最麻烦的是版本兼容性——滚动过程中,新旧版本会同时在线提供服务。如果你的新版本改了API接口或者数据库结构,老版本还在处理请求,很容易出问题。
下面是一个典型的 Kubernetes 滚动更新配置:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
replicas: 10
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 2 # 允许最多超出 2 个实例
maxUnavailable: 1 # 允许最多 1 个实例不可用
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-app
image: my-app:2.0.0
readinessProbe: # 就绪探针,确保新实例真正就绪
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
滚动更新的优缺点:
- 优点: 无需额外资源、零停机、自动化程度高、适合大规模集群。
- 缺点: 回滚复杂(需要再滚动一次)、新旧版本兼容性要求高、更新速度相对较慢。
- 适用场景: 资源有限的环境、无状态服务、微服务架构中的大部分非核心服务。
2.5 三种策略对比
| 策略 | 切换速度 | 资源成本 | 风险等级 | 回滚难度 | 流量控制粒度 |
|---|---|---|---|---|---|
| 蓝绿部署 | 秒级 | 高(2倍资源) | 低 | 低 | 全量 |
| 金丝雀发布 | 分钟级~小时级 | 中(N+少量) | 低 | 中 | 百分比 |
| 滚动更新 | 分钟级 | 低(N) | 中 | 高 | 实例级 |
2.6 怎么选?我的几条原则
说实话,没有标准答案。但我可以分享几条我自己的判断依据:
- 业务容忍度: 如果出问题10秒就有人投诉,选蓝绿或金丝雀。如果业务天然能容忍短时波动,滚动更新完全够用。
- 基础设施预算: 有钱上蓝绿,没钱上滚动。金丝雀居中,但需要流量控制组件(比如Service Mesh或Ingress Controller)。
- 团队运维能力: 蓝绿最「笨」但最稳,滚动最「聪明」但对兼容性要求高。团队如果还在爬坡期,别搞太复杂的灰度策略。
- 系统架构: 有状态服务(比如数据库)别轻易搞滚动,蓝绿配合双写更安全。无状态服务可以放心用滚动。
三种策略不是互斥的。我在一些大型项目里,核心服务用蓝绿,普通服务用滚动,新功能灰度用金丝雀。它们可以共存,关键是你得清楚每种策略的适用边界。