用权重、请求头、镜像把金丝雀跑起来
目标
能够根据场景选择权重、请求头、镜像这三种流量拆分方式,并制定明确写出回滚条件的金丝雀计划。
为什么重要
金丝雀发布的本质不是“分一点流量”,而是**“预先决定何时停止”。任何人都能提高权重,但如果把看到不良指标后是否回滚的判断交给人,就容易动摇。因此,需要在每个阶段写明判断标准,并让该标准直接成为自动化的输入。另一个重点是将 Pod 数量与流量比例分离**。在服务网格中,即使新版本 Pod 已全部启动,也可以保持 0% 流量;发现问题时,无需重新部署,只需把权重恢复为 0。
本实验混合了两种评分方式。 第 1、2、4、5 步查看保存的文件,第 6、7、8 步查看实际应用到集群的状态。因此,每一步都必须单独保留文件;如果持续覆盖同一个文件,前面的步骤会再次失败。每个 vs-*.yaml 文件中只能放置一个 VirtualService 文档(若一个文件包含多个文档,评分器无法确定第一个文档)。
步骤
开始前的准备。 每次实验都会启动新的实验 Pod,因此不会保留上一个实验的服务网格配置。如果 kubectl get crd virtualservices.networking.istio.io 没有输出,请先运行 istioctl manifest generate --set profile=minimal > /root/istio/manifest.yaml,然后将 kubectl apply -f /root/istio/manifest.yaml 执行两次,再用 kubectl create ns mesh-lab && kubectl label ns mesh-lab istio-injection=enabled 创建命名空间。第 6 步会通过标签查询存活的 Pod,因此必须等待夹具工作负载的 Pod 进入 Running 状态。
- 首先把
/opt/lab/fixtures/istio/workload-v1v2.yaml应用到mesh-lab,并应用一个 DestinationRule,其spec.subsets包含v1(labels: {version: v1})和v2(labels: {version: v2}),名称为reviews。然后创建/root/istio/canary/vs-baseline.yaml:其中只含一个 VirtualService,spec.http[0].route中恰好有两个条目,subset: v1的weight为 100,subset: v2的weight为 0。 - 创建
/root/istio/canary/vs-90-10.yaml。v1 使用weight: 90,v2 使用weight: 10(总和为 100)。对该文件执行kubectl apply,并把输出保存到/root/istio/canary/out/applied-10.txt(必须看到configured/created/unchanged之一)。 - 创建一个权重总和不为 100 的文件(例如在
/root/istio/canary/vs-bad.yaml中设置 v1 90 / v2 20),使用istioctl validate -f检查,并把拒绝消息连同标准错误保存到/root/istio/canary/out/weight-error.txt。另外,在/root/istio/canary/out/weight-note.txt中写明权重总和必须为 100 的规则。 - 创建
/root/istio/canary/vs-header.yaml。把选择请求头x-canary恰好等于true的路由放在前面,目标为subset: v2、weight: 100。随后再放置一条无条件的默认路由(条件路由不能放在最后)。 - 创建
/root/istio/canary/vs-mirror.yaml。spec.http[0].route指向subset: v1,且weight: 100;在同一条目中设置mirror(host: reviews、subset: v2)和mirrorPercentage.value: 10。然后在/root/istio/canary/out/mirror-note.txt中写明镜像请求的响应会被丢弃,以及写操作可能带来的副作用风险。 - 首先重新应用
vs-90-10.yaml,使配置同时引用 v1、v2。然后暂时将 DestinationRulereviews的 subset 名称v2改为v2-canary并应用,把istioctl analyze -n mesh-lab的结果保存到/root/istio/canary/out/analyze-mismatch.txt。将名称恢复为v2(labelsversion: v2)并应用后,再次分析并保存到/root/istio/canary/out/analyze-clean.txt(其中不得有Error [)。 - 向 DestinationRule
reviews添加并应用trafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-id。然后在/root/istio/canary/out/sticky-note.txt(至少 50 字节)中说明同一用户在不同版本之间来回切换为何会造成问题。 - 创建
/root/istio/canary/rollout.yaml。顶层必须包含stages数组(至少 5 个阶段)和rollback键。每个 stage 都必须同时包含weight(v2 权重)与criteria(进入下一阶段的判断标准);weight 从 0 开始、以 100 结束,且中间不得降低。最后,把实际 VirtualServicereviews应用为 v1 50 / v2 50(以spec.http的最后一个条目为准)。将istioctl analyze -n mesh-lab的结果保存到/root/istio/canary/out/final-analyze.txt,且不得有错误。
参考
- 每次实验都会启动新的实验 Pod,因此不会保留上一个实验的集群状态。所以,用清单保留服务网格配置本身就意味着可复现性。本实验要求每一步单独保留文件,原因也相同:集群即使消失,文件仍会保留。
- 首先使用
kubectl get pods -n mesh-lab -l app=reviews --show-labels,确认 Pod 实际带有version标签。第 6 步的评分器会通过该标签寻找 Pod。 - 第 3 步的
istioctl validate会以失败结束,因此请像istioctl validate -f 파일 > 출력 2>&1 || true这样保存输出。 - 在第 6 步更改 subset 的名称后,VirtualService 引用的
v2会消失,静态分析会立即发现。这个实验比只更改标签更确定。 - 第 8 步的
rollout.yaml不是 Istio 资源,而是你设计的计划文件。格式可以自由设计,但stages、weight、criteria、rollback这些键名必须保持不变。 - 常见错误 1:不断修改并覆盖同一个文件。每一步都必须使用不同文件,才能保留前面步骤的评分结果。
- 常见错误 2:在第 5 步省略 v1 的
weight: 100。只有一个目标时即使省略也能工作,但最好在清单中明确表明镜像不会改变实际响应。
创建 100/0 起点清单
首先把 /opt/lab/fixtures/istio/workload-v1v2.yaml 应用到 mesh-lab,并应用一个 DestinationRule,其 spec.subsets 包含 v1(labels: {version: v1})和 v2(labels: {version: v2}),名称为 reviews。然后创建 /root/istio/canary/vs-baseline.yaml:其中只含一个 VirtualService,spec.http[0].route 中恰好有两个条目,subset: v1 的 weight 为 100,subset: v2 的 weight 为 0。
新版本已经部署,但尚未分配流量。把两个 subset 都写好后,从下一步开始只需修改数字。
将 10% 流量转移到新版本
创建 /root/istio/canary/vs-90-10.yaml。v1 使用 weight: 90,v2 使用 weight: 10(总和为 100)。对该文件执行 kubectl apply,并把输出保存到 /root/istio/canary/out/applied-10.txt(必须看到 configured/created/unchanged 之一)。
不要覆盖上一步的文件,请另存为新文件。应用结果的输出也必须作为证据保存。
观察权重总和错误时会发生什么
创建一个权重总和不为 100 的文件(例如在 /root/istio/canary/vs-bad.yaml 中设置 v1 90 / v2 20),使用 istioctl validate -f 检查,并把拒绝消息连同标准错误保存到 /root/istio/canary/out/weight-error.txt。另外,在 /root/istio/canary/out/weight-note.txt 中写明权重总和必须为 100 的规则。
特意创建错误文件并交给验证工具检查。拒绝消息本身就是本步骤的产物。由于命令会以失败结束,必须连同标准错误一起保存。
本步骤的关键是了解哪些错误会被发现、哪些不会。即使总和为 110,目前 istioctl 也会通过,因为 Envoy 改为按 total_weight 归一化后,验证器取消了总和必须为 100 的规则。相反,总和为 0 会被拒绝。请同时尝试两种情况并保留结果。你将在这里学到:验证工具无法发现所有错误。
只将内部测试人员送往新版本
创建 /root/istio/canary/vs-header.yaml。把选择请求头 x-canary 恰好等于 true 的路由放在前面,目标为 subset: v2、weight: 100。随后再放置一条无条件的默认路由(条件路由不能放在最后)。
指定人员必须 100% 看到新版本。条件路由应位于默认路径之上,无条件的默认路径放在最后。
配置会丢弃响应的镜像流量
创建 /root/istio/canary/vs-mirror.yaml。spec.http[0].route 指向 subset: v1,且 weight: 100;在同一条目中设置 mirror(host: reviews、subset: v2)和 mirrorPercentage.value: 10。然后在 /root/istio/canary/out/mirror-note.txt 中写明镜像请求的响应会被丢弃,以及写操作可能带来的副作用风险。
镜像不会改变返回给用户的响应。实际流量仍由旧版本 100% 处理,只有副本会发送到新版本。不要忘记指定比例。
制造并修复 subset 与 Pod 标签不一致
首先重新应用 vs-90-10.yaml,使配置同时引用 v1、v2。然后暂时将 DestinationRule reviews 的 subset 名称 v2 改为 v2-canary 并应用,把 istioctl analyze -n mesh-lab 的结果保存到 /root/istio/canary/out/analyze-mismatch.txt。将名称恢复为 v2(labels version: v2)并应用后,再次分析并保存到 /root/istio/canary/out/analyze-clean.txt(其中不得有 Error [)。
如果路由引用的 subset 从定义中消失,静态分析会发现。分别保留不一致状态与修复后状态的分析结果。
将同一用户固定到一个版本
向 DestinationRule reviews 添加并应用 trafficPolicy.loadBalancer.consistentHash.httpHeaderName: x-user-id。然后在 /root/istio/canary/out/sticky-note.txt(至少 50 字节)中说明同一用户在不同版本之间来回切换为何会造成问题。
权重拆分会针对每个请求重新选择。将负载均衡器改为基于哈希,并指定使用哪个请求头作为键。
制定分阶段金丝雀计划并推进到中间阶段
创建 /root/istio/canary/rollout.yaml。顶层必须包含 stages 数组(至少 5 个阶段)和 rollback 键。每个 stage 都必须同时包含 weight(v2 权重)与 criteria(进入下一阶段的判断标准);weight 从 0 开始、以 100 结束,且中间不得降低。最后,把实际 VirtualService reviews 应用为 v1 50 / v2 50(以 spec.http 的最后一个条目为准)。将 istioctl analyze -n mesh-lab 的结果保存到 /root/istio/canary/out/final-analyze.txt,且不得有错误。
计划的每个阶段都需要权重与判断标准,整体还需要回滚方法。并将实际服务网格推进到中间阶段。