在项目持续迭代与研发交付过程中,上线部署几乎是每个团队都必须面对的关键环节。当前主流的部署策略主要包括三种:金丝雀升级(又称灰度部署)、蓝绿升级与滚动升级。本文将重点聚焦金丝雀升级,并深入讲解它在 Kubernetes 环境中的具体落地实践。
金丝雀部署,也常被称为灰度发布,其核心思路是:在版本升级时,先让一小部分用户试用新版本,而大多数用户仍然使用稳定版。如果新版本运行顺畅、无异常,便逐步扩大使用范围,直到所有用户都平滑迁移到新版本。这种策略的最大价值在于:既能最大限度保障系统整体稳定性,又能在早期快速发现风险、及时控制损失,避免因一次升级导致整个项目出现重大故障。下面这张图清晰地展示了整个过程。
光看理论还不够直观,我们通过一个真实案例,演示如何在 Kubernetes 中一步步操作金丝雀升级。
实战演示:在 Kubernetes 中实现金丝雀升级
(1)创建文件 canary-demo-v1.yaml,内容如下:
apiVersion: v1
kind: Service
metadata:
name: canary-demo
labels:
app: canary-demo
spec:
type: NodePort
ports:
- name: http
port: 80
targetPort: http
selector:
app: canary-demo
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-demo-v1
labels:
app: canary-demo
spec:
replicas: 10
selector:
matchLabels:
app: canary-demo
version: v1.0.0
template:
metadata:
labels:
app: canary-demo
version: v1.0.0
spec:
containers:
- name: canary-demo
image: collenzhao/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
env:
- name: VERSION
value: v1.0.0
# 这里利用 Service 的标签选择器实现了多个 Deployment 之间的负载均衡。
(2)应用该文件:
kubectl apply -f canary-demo-v1.yaml
(3)查看 Service 信息:
kubectl get service canary-demo
# 输出:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
canary-demo NodePort 10.1.119.250 80:30952/TCP 4s
(4)通过 Service 访问 Deployment 验证当前版本:
curl 10.1.119.250:80
# 输出:
Host: canary-demo-v1-78b6cd78db-skjng, Version: v1.0.0
# 可以看到当前运行的是 v1.0.0 版本。
(5)准备进行金丝雀升级,创建 canary-demo-v2.yaml:
apiVersion: apps/v1
kind: Deployment
metadata:
name: canary-demo-v2
labels:
app: canary-demo
spec:
replicas: 1
selector:
matchLabels:
app: canary-demo
version: v2.0.0
template:
metadata:
labels:
app: canary-demo
version: v2.0.0
spec:
containers:
- name: canary-demo
image: collenzhao/k8s-deployment-strategies
ports:
- name: http
containerPort: 8080
env:
- name: VERSION
value: v2.0.0
(6)开启两个命令行窗口,分别实时监控 Deployment 和 Pod 的变化:
kubectl get --watch deployment
kubectl get --watch pod
(7)执行升级操作:
kubectl apply -f canary-demo-v2.yaml
(8)观察 Deployment 和 Pod 的动态变化,效果如下图所示:
注意观察:v1.0.0 版本有 10 个实例,而 v2.0.0 版本只有 1 个实例——这正是金丝雀部署中“一小撮”用户尝鲜的体现。
(9)编写一个脚本模拟请求,看看流量如何分配:
for a in {1..11}
do
sleep 1;
curl "10.1.119.250:80";
done
# 输出:
Host: canary-demo-v1-78b6cd78db-nbbjx, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-nbbjx, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-67cg5, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-gd9kf, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-7zjwf, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-gd9kf, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-dskpc, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-gd9kf, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-67cg5, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-fdrwp, Version: v1.0.0
Host: canary-demo-v2-7c4c5f5444-g69jr, Version: v2.0.0
# 循环 11 次请求中,10 次命中 v1.0.0,1 次命中 v2.0.0,流量比例正好是 10:1。
(10)确认新版本运行正常后,逐步调整实例比例。将 v2.0.0 扩容到 5 个,同时将 v1.0.0 缩容到 5 个:
kubectl scale --replicas=5 deploy canary-demo-v2
kubectl scale --replicas=5 deploy canary-demo-v1
(11)观察 Deployment 变化:
kubectl get --watch deployment

(12)再次执行脚本,验证流量分配是否变成 1:1:
for a in {1..10}
do
sleep 1;
curl "10.1.119.250:80";
done
# 输出:
Host: canary-demo-v1-78b6cd78db-67cg5, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-9dphd, Version: v1.0.0
Host: canary-demo-v2-7c4c5f5444-lcbhw, Version: v2.0.0
Host: canary-demo-v1-78b6cd78db-hr9x8, Version: v1.0.0
Host: canary-demo-v1-78b6cd78db-7zjwf, Version: v1.0.0
Host: canary-demo-v2-7c4c5f5444-lcbhw, Version: v2.0.0
Host: canary-demo-v1-78b6cd78db-fdrwp, Version: v1.0.0
Host: canary-demo-v2-7c4c5f5444-9hbwr, Version: v2.0.0
Host: canary-demo-v2-7c4c5f5444-9hbwr, Version: v2.0.0
Host: canary-demo-v1-78b6cd78db-hr9x8, Version: v1.0.0
# 10 次请求中,v1 和 v2 各占一半,符合预期。
(13)确认新版本完全稳定后,删除旧版本,并将 v2.0.0 扩容到 10 个实例:
kubectl delete deployment.apps/canary-demo-v1
kubectl scale --replicas=10 deploy canary-demo-v2
# 此时应用已全部升级到 v2.0.0。再执行 for 循环,所有请求均返回:
Host: canary-demo-v2-7c4c5f5444-g69jr, Version: v2.0.0
Host: canary-demo-v2-7c4c5f5444-lcbhw, Version: v2.0.0
Host: canary-demo-v2-7c4c5f5444-hs4k2, Version: v2.0.0
... 全部为 v2.0.0
(14)最后清理测试数据:
kubectl delete all -l app=canary-demo
纵观整个流程,核心思想其实非常简单:通过动态调整新旧版本的实例数量比例,逐步将流量从旧版本平滑引导到新版本。每一步都可以实时观察、随时回滚,这正是生产环境中真正可靠的部署方式。
