Istio金丝雀发布实战:Kubernetes生产环境渐进式上线指南

发布时间:2026/6/22 15:45:40
Istio金丝雀发布实战:Kubernetes生产环境渐进式上线指南 1. 什么是金丝雀发布它为什么不是“高级灰度”而是生产环境的生存技能你刚在Kubernetes集群里跑通了一个新版本服务API响应快了30%日志结构也更清晰——但上线前那几秒手心还是冒汗。不是因为技术不熟而是因为你清楚哪怕一个微小的配置错误、一次未被Mock的第三方依赖超时、或者某个边缘路径下内存泄漏的缓慢积累都可能在流量洪峰中被指数级放大把整个订单链路拖进雪崩。这时候Istio不是锦上添花的“服务网格玩具”而是你手里那根系在悬崖边的保险绳canary deployments金丝雀发布也不是教科书里抽象的“渐进式发布概念”它是你在真实生产环境中用5%的流量去替全量用户踩雷的战术动作。我做过7个不同行业的K8s平台落地从金融核心交易系统到电商大促后台所有团队最终都收敛到同一个结论没有金丝雀能力的Kubernetes集群本质上只是个更复杂的单体部署工具。为什么因为K8s原生的RollingUpdate只能保证“旧Pod死一个、新Pod起一个”它不关心新版本在真实用户请求下的行为是否健康。而Istio的流量治理能力恰恰补上了这最关键一环——它让“把100个请求中的5个发给新版本”这件事从需要改代码、写脚本、手动切DNS的高危操作变成一条YAML就能声明的、可审计、可回滚、可监控的基础设施能力。这个标题里的三个关键词必须拆开揉碎理解Kubernetes是舞台Istio是导演金丝雀发布是剧本。舞台搭得再漂亮没有导演调度演员服务只会乱撞导演再厉害没有精心设计的剧本金丝雀策略再好的演员也可能演砸。所以本文不讲“如何安装K8s”Ubuntu 22.04装集群kubekey一键生成这些是地基不是上层建筑也不堆砌Istio的CRD定义VirtualService、DestinationRule这些名词背后到底在解决什么问题。我们直接进入战场当你已经有一个运行中的K8s集群和Istio控制平面如何用最短路径、最少配置、最高确定性把一个新版本服务像外科手术一样精准地、安全地推送到生产环境。你会看到真实的YAML片段、实测的Prometheus查询语句、Grafana看板截图背后的逻辑以及我踩过的那些“文档里绝不会写但线上一定会爆”的坑。2. 整体架构设计与方案选型为什么不用Ingress也不用手写Envoy配置2.1 金丝雀发布的三种实现层级对比从脆弱到健壮在K8s生态里实现流量分发有至少三条路但它们的稳定性和运维成本天差地别第一层K8s Service NodePort/LoadBalancer这是最原始的方式给新版本服务单独建一个Service用外部LB做DNS轮询或权重配置。问题在哪完全脱离K8s的Service Mesh体系。你无法基于HTTP Header、URL Path、甚至用户ID做路由无法获取新旧版本的精细化指标比如新版本的5xx错误率是否突然飙升一旦出问题回滚要手动改LB配置耗时以分钟计。我见过某团队用这种方式做“金丝雀”结果新版本因一个未处理的JWT过期异常导致大量401但监控只显示“整体错误率上升”根本分不清是新版本还是老版本的问题——因为指标是聚合的。第二层K8s Ingress Controller如Nginx Ingress比第一层强支持基于Host、Path的路由也能配权重通过nginx.ingress.kubernetes.io/canary-weight注解。但它本质仍是七层代理无法感知服务间的调用链路。比如你的前端服务调用后端APIIngress只能控制“用户到前端”的流量却管不了“前端到后端”的调用是否也按比例分发。更致命的是Ingress的权重配置是全局的无法针对特定用户群体如内测用户做定向引流。当业务方提出“让所有VIP用户先用新功能”Ingress就彻底歇菜。第三层Istio Service Mesh本文采用这是唯一能同时满足“细粒度路由全链路可观测策略驱动回滚”的方案。Istio的SidecarEnvoy注入到每个Pod里所有进出流量都经过它。这意味着路由决策发生在应用层HTTP Header、Cookie、Query Param而非网络层指标采集是服务对服务的frontend → backend-v1 vs frontend → backend-v2颗粒度精确到每次调用策略执行是声明式的YAML定义变更即生效无需重启任何组件回滚是原子性的把VirtualService里v2的权重从5%改成0%瞬间完成。提示不要被“Istio复杂”吓退。我们只用它最核心的两个CRDVirtualService定义流量怎么走和DestinationRule定义流量走到哪、怎么走。其他如Gateway、PeerAuthentication等在金丝雀场景里非必需强行引入反而增加故障面。2.2 Istio版本选择为什么坚持用1.18而不是追最新版Istio的版本迭代极快但生产环境不是实验室。我强烈建议在2024年将Istio 1.18.x作为金丝雀发布的基准线。原因很实际1.17及之前版本的VirtualService权重路由存在已知缺陷当权重设置为5代表5%时实际流量分配并非严格5%而是在[3%, 7%]区间波动。这是Envoy底层负载均衡器的随机算法导致的官方Issue #38216明确记录。对于需要精确控制风险暴露面的金丝雀这种不确定性是不可接受的。1.18引入了consistentHash负载均衡策略的增强配合VirtualService的http.route.weight能实现真正稳定的5%流量切分。实测数据在10万QPS压力下1.18的流量偏差稳定在±0.3%以内。1.19版本虽然增加了更多特性如WASM插件但其Sidecar注入的默认资源限制CPU 100m, Memory 128Mi在高并发场景下容易触发OOMKilled。我们曾在线上遇到过一个峰值QPS 5k的订单服务Sidecar因内存不足被杀导致所有请求503——而这个问题在1.18的默认配置下从未发生。注意如果你的集群还在用Istio 1.16或更早请务必升级。升级不是“锦上添花”而是“堵住生产漏洞”。升级路径很清晰1.16 → 1.17跳过因上述缺陷→ 1.18。升级过程本身有成熟文档但关键点在于升级前必须备份所有VirtualService和DestinationRule的YAML并在升级后逐条验证路由是否生效。我吃过亏——某次升级后一个DestinationRule的trafficPolicy配置因字段名变更失效导致所有金丝雀流量被默认路由到v1新版本形同虚设。2.3 集群准备检查清单5分钟确认你的环境ready在写第一行YAML前请用以下命令快速验证环境是否具备金丝雀基础# 1. 确认Istio控制平面健康重点看istiod状态 kubectl get pods -n istio-system | grep istiod # ✅ 正常输出istiod-7c8d9b5f4-abcde 1/1 Running 0 3d # 2. 确认目标命名空间已启用Sidecar自动注入 kubectl get namespace your-app-ns -o jsonpath{.metadata.labels.istio-injection} # ✅ 正常输出enabled 若为空则需执行kubectl label namespace your-app-ns istio-injectionenabled # 3. 确认应用Pod已注入Sidecar看容器数是否为2 kubectl get pods -n your-app-ns | grep your-app # ✅ 正常输出your-app-v1-5c7d9b5f4-xyzab 2/2 Running 0 1h # ❌ 错误输出your-app-v1-5c7d9b5f4-xyzab 1/1 Running 0 1h 缺少istio-proxy容器 # 4. 快速测试Istio路由能力创建一个临时VS看是否生效 cat EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: test-vs namespace: your-app-ns spec: hosts: - * http: - route: - destination: host: your-app.your-app-ns.svc.cluster.local subset: v1 weight: 100 EOF # 然后curl你的服务入口确认返回正常。如果失败说明Istio数据面未就绪。这四步检查我称之为“金丝雀启动前的安检”。跳过它后面所有配置都可能白忙一场。尤其注意第3步——Sidecar注入失败是新手最常见的卡点。常见原因命名空间label没打、Pod的spec.template.spec.containers里指定了securityContext且与Istio的默认策略冲突、或者集群启用了PodSecurityPolicyPSP但未授权Istio的ServiceAccount。这些问题在kubectl describe pod的Events里都有明确报错但很多人习惯性忽略。3. 核心细节解析与实操要点VirtualService与DestinationRule的黄金搭档3.1 DestinationRule不是“规则”而是“服务画像”很多初学者把DestinationRule当成简单的“路由规则”这是巨大误解。它的核心作用是为一个服务host定义其所有可用的子集subsets并为每个子集指定连接策略。你可以把它理解成服务的“身份证健康档案”。看一个典型DestinationRuleapiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: your-app-dr namespace: your-app-ns spec: host: your-app.your-app-ns.svc.cluster.local subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 trafficPolicy: connectionPool: http: http1MaxPendingRequests: 100 maxRequestsPerConnection: 10 tcp: maxConnections: 100 outlierDetection: consecutive5xxErrors: 5 interval: 30s baseEjectionTime: 30s这里的关键点subsets定义了v1和v2两个子集它们的区分依据是Pod的Labelversion: v1。这意味着你必须确保部署v1和v2的Deployment其Pod模板里有对应的version标签。这是Istio识别版本的基础缺一不可。trafficPolicy里的outlierDetection异常检测是金丝雀的生命线。它告诉Sidecar“如果某个v2 Pod连续5次返回5xx就把它从负载均衡池里踢出去30秒”。这比K8s的Liveness Probe更精细——Probe只管进程是否存活而Istio的异常检测管的是业务层面的健康。当v2版本因数据库连接池耗尽开始返回500时这个策略能自动隔离故障Pod避免流量继续打过去放大问题。实操心得outlierDetection的参数必须根据你的服务SLA调整。比如金融类服务要求99.99%可用性consecutive5xxErrors可以设为3interval缩到10s而内部管理后台设为5和30s更稳妥。盲目套用文档值会导致误踢健康Pod被踢或漏踢故障Pod迟迟不被隔离。3.2 VirtualService流量的“交通指挥中心”如果说DestinationRule画出了服务的“地图”那么VirtualService就是指挥交通的“红绿灯”。它定义了“谁的请求、在什么条件下、流向哪个子集”。一个标准的金丝雀VirtualService长这样apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: your-app-vs namespace: your-app-ns spec: hosts: - your-app.example.com # 对外暴露的域名 gateways: - your-app-gateway # 流量入口网关 http: - match: - headers: cookie: regex: ^(.*?;)?(user_typeinternal)(;.*)?$ # 匹配Cookie里有user_typeinternal的请求 route: - destination: host: your-app.your-app-ns.svc.cluster.local subset: v2 weight: 100 # 100%内部用户走v2 - match: - headers: user-agent: regex: .*Chrome.* # 匹配Chrome浏览器 route: - destination: host: your-app.your-app-ns.svc.cluster.local subset: v2 weight: 5 # Chrome用户5%走v2 - route: - destination: host: your-app.your-app-ns.svc.cluster.local subset: v1 weight: 95 # 其余95%流量走v1 - destination: host: your-app.your-app-ns.svc.cluster.local subset: v2 weight: 5 # 其余5%流量走v2默认金丝雀这个配置展示了金丝雀的三种典型模式定向引流Targeted Canary通过Cookie匹配内部员工100%流量走v2。这是灰度测试的黄金标准——让可信用户先用快速收集反馈。设备/浏览器引流Browser-based CanaryChrome用户有5%概率看到新版本。利用浏览器UA的广泛性低成本覆盖大量真实用户。比例引流Weight-based Canary全局5%流量随机分发到v2。这是最保守的起点适合对新版本信心不足时。关键原理Istio的匹配规则是顺序执行、首个匹配即生效。所以上面的配置里定向引流必须放在最前面否则会被后面的“全局5%”规则截获。这点和Nginx的location匹配逻辑一致但新手常犯的错误是把权重规则放最前导致定向规则永远不触发。3.3 金丝雀发布的完整生命周期从部署到回滚的7个步骤真正的金丝雀不是“配完YAML就完事”而是一个闭环流程。以下是我在生产环境反复验证的7步法准备阶段确保v2版本的Deployment已部署且Pod带version: v2标签DestinationRule已创建包含v2子集VirtualService初始配置为100% v1。预热阶段将VirtualService中v2的权重设为1%观察10分钟。重点看v2 Pod的CPU/Memory是否突增可能有内存泄漏Prometheus中istio_requests_total{destination_serviceyour-app, destination_versionv2}的5xx错误率是否0.1%。探测阶段权重升至5%同时开启定向引流如内部用户100%走v2。此时让QA团队用内部账号深度测试所有核心路径并监控istio_request_duration_seconds_bucket{destination_versionv2}的P95延迟是否显著高于v1。扩展阶段若探测无异常权重升至20%并添加浏览器引流Chrome用户100%走v2。目的是用真实用户行为压测观察istio_requests_total{response_code~4.*|5.*}的分布。评估阶段保持20%权重2小时拉取Grafana看板对比v1/v2的四大黄金指标错误率Error Rate延迟Latency P95QPSQueries Per SecondSidecar CPU使用率container_cpu_usage_seconds_total{containeristio-proxy}若v2的任一指标劣于v1超过10%立即进入回滚。全量阶段所有指标达标后将VirtualService中v1的权重设为0v2设为100%。注意不要删除v1的Deployment保留它至少24小时作为紧急回滚的“热备”。清理阶段v2稳定运行24小时后删除v1的Deployment和DestinationRule中的v1子集。此时VirtualService可简化为单一路由。注意事项每一步的权重调整都应通过kubectl apply -f vs.yaml执行严禁手动编辑已存在的VS对象。因为Istio的CRD更新是乐观锁机制手动编辑可能因版本冲突导致配置丢失。我曾因直接kubectl edit vs修改权重结果另一个同事同时提交了新路由我的修改被覆盖导致金丝雀流量意外中断。4. 实操过程与核心环节实现从零开始部署一个可验证的金丝雀4.1 环境初始化用最小化YAML搭建验证环境我们不依赖任何外部应用用Istio自带的httpbin服务做演示。它足够简单返回请求头、状态码又能充分验证金丝雀能力。第一步部署v1版本的httpbin# 创建命名空间并启用注入 kubectl create namespace canary-demo kubectl label namespace canary-demo istio-injectionenabled # 部署v1带versionv1标签 cat EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: httpbin-v1 namespace: canary-demo spec: replicas: 2 selector: matchLabels: app: httpbin version: v1 template: metadata: labels: app: httpbin version: v1 spec: containers: - image: docker.io/kennethreitz/httpbin imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 80 EOF第二步创建Service和DestinationRule# Service必须定义否则Istio无法识别服务 cat EOF | kubectl apply -f - apiVersion: v1 kind: Service metadata: name: httpbin namespace: canary-demo labels: app: httpbin spec: ports: - name: http port: 80 protocol: TCP targetPort: 80 selector: app: httpbin EOF # DestinationRule定义v1和即将创建的v2 cat EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: httpbin-dr namespace: canary-demo spec: host: httpbin.canary-demo.svc.cluster.local subsets: - name: v1 labels: version: v1 - name: v2 labels: version: v2 EOF第三步创建初始VirtualService100% v1cat EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-vs namespace: canary-demo spec: hosts: - httpbin.example.com http: - route: - destination: host: httpbin.canary-demo.svc.cluster.local subset: v1 weight: 100 EOF此时所有访问httpbin.example.com的请求都会打到v1 Pod。用curl -H Host: httpbin.example.com http://INGRESS_GATEWAY_IP验证返回正常。4.2 发布v2并启动金丝雀5行命令完成流量切换第四步部署v2版本仅改镜像和标签# 部署v2用不同镜像便于区分 cat EOF | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: httpbin-v2 namespace: canary-demo spec: replicas: 2 selector: matchLabels: app: httpbin version: v2 template: metadata: labels: app: httpbin version: v2 spec: containers: - image: docker.io/kennethreitz/httpbin:latest # 用latest镜像行为略有不同 imagePullPolicy: IfNotPresent name: httpbin ports: - containerPort: 80 EOF第五步更新VirtualService启动5%金丝雀# 将VS更新为95% v1 5% v2 cat EOF | kubectl apply -f - apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: httpbin-vs namespace: canary-demo spec: hosts: - httpbin.example.com http: - route: - destination: host: httpbin.canary-demo.svc.cluster.local subset: v1 weight: 95 - destination: host: httpbin.canary-demo.svc.cluster.local subset: v2 weight: 5 EOF第六步验证流量分发核心技巧如何证明5%的流量真的打到了v2不能靠猜要用Sidecar的日志# 获取一个v1 Pod的istio-proxy容器日志 kubectl logs -n canary-demo httpbin-v1-5c7d9b5f4-abcde -c istio-proxy | grep httpbin.canary-demo.svc.cluster.local | tail -10 # 输出示例 [2024-06-15T08:22:10.123Z] GET /headers HTTP/1.1 200 - - - 123 543 45 - 10.244.1.5 curl/7.68.0 a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8 httpbin.example.com 10.244.2.6:80 outbound|80||httpbin.canary-demo.svc.cluster.local 10.244.1.5:54321 10.244.2.6:80 10.244.1.5:54320 - default # 关键字段outbound|80||httpbin.canary-demo.svc.cluster.local 表示目标服务 # 10.244.2.6:80 是目标Pod IP用kubectl get pods -o wide查对应version更高效的方法是用istioctl命令# 查看当前流量路由详情 istioctl proxy-config routes -n canary-demo httpbin-v1-5c7d9b5f4-abcde | grep -A 10 httpbin.canary-demo # 输出会显示类似 # Route: http.80 # Cluster: outbound|80||httpbin.canary-demo.svc.cluster.local # Weight: 95 (v1), 5 (v2)4.3 监控与指标采集用Prometheus定位v2的“隐性故障”金丝雀最大的陷阱是v2看起来“一切正常”但实际在悄悄劣化。比如内存泄漏v2 Pod的RSS内存每小时增长50MB但CPU不高不易被告警捕获连接池耗尽v2的数据库连接数达到上限新请求排队P95延迟从100ms升到800ms日志污染v2因调试代码打印了大量INFO日志导致磁盘IO飙升。这些都需要针对性监控。以下是必须配置的Prometheus查询监控目标Prometheus查询语句说明v2错误率突增sum(rate(istio_requests_total{destination_servicehttpbin.canary-demo.svc.cluster.local, destination_versionv2, response_code~5.*}[5m])) by (destination_version) / sum(rate(istio_requests_total{destination_servicehttpbin.canary-demo.svc.cluster.local, destination_versionv2}[5m])) by (destination_version)计算v2的5xx错误率阈值设为0.5%v2延迟劣化histogram_quantile(0.95, sum(rate(istio_request_duration_seconds_bucket{destination_servicehttpbin.canary-demo.svc.cluster.local, destination_versionv2}[5m])) by (le, destination_version))v2的P95延迟对比v1差异20%即告警v2 Sidecar内存泄漏container_memory_working_set_bytes{namespacecanary-demo, containeristio-proxy, pod~httpbin-v2.*}设置告警30分钟内增长300MBv2连接池饱和istio_tcp_connections_opened_total{destination_servicehttpbin.canary-demo.svc.cluster.local, destination_versionv2} - istio_tcp_connections_closed_total{destination_servicehttpbin.canary-demo.svc.cluster.local, destination_versionv2}当前打开连接数超过1000需关注实操心得不要等告警才看指标。在金丝雀启动后立刻打开Grafana新建一个Dashboard把上述四个Panel并排显示。我习惯把v1/v2的指标曲线用不同颜色画在同一张图上一眼就能看出差异。曾经发现v2的P95延迟曲线在凌晨3点准时上扬——排查发现是v2版本新增了一个定时任务每小时扫一次全表而v1没有。这种“时间规律性劣化”只有实时盯盘才能捕捉。5. 常见问题与排查技巧实录那些让SRE半夜爬起来的坑5.1 问题速查表金丝雀不生效的7种可能及解决方案现象可能原因排查命令解决方案所有流量都走v1v2完全收不到请求DestinationRule中v2子集的labels与v2 Pod的metadata.labels不匹配kubectl get pods -n canary-demo -l versionv2 --show-labels和kubectl get dr httpbin-dr -n canary-demo -o yaml对比确保Pod标签和DR子集标签完全一致包括空格流量按比例分发但v2的错误率远高于v1且Sidecar日志显示大量upstream connect errorv2 Pod的readinessProbe未配置或探针失败导致Pod虽Running但未加入Endpointkubectl get endpoints httpbin -n canary-demo和kubectl describe pod -n canary-demo httpbin-v2-xxxx为v2添加readinessProbe确保它只在真正就绪时接收流量VirtualService更新后流量分配比例不稳定有时v2占10%有时占2%Istio 1.17及以下版本的权重算法缺陷istioctl version确认版本升级到Istio 1.18或改用consistentHash策略需在DR中配置定向引流如Cookie匹配不生效VirtualService中match规则顺序错误被后面的全局规则覆盖kubectl get vs httpbin-vs -n canary-demo -o yaml检查match顺序把定向规则移到VS的最上方确保优先匹配v2 Pod的CPU使用率飙升但应用日志无异常SidecarEnvoy的TLS握手开销过大v2版本启用了mTLS但v1没有kubectl top pods -n canary-demo和istioctl proxy-status统一所有版本的mTLS策略或在DestinationRule中禁用trafficPolicy.tls.mode: DISABLE金丝雀流量中部分请求返回404VirtualService的hosts字段与Ingress Gateway的server.hosts不匹配kubectl get gateway your-app-gateway -n istio-system -o yaml对比确保VS的hosts值在Gateway的server.hosts列表中回滚时流量未能立即切回v1VirtualService更新后Envoy配置推送有延迟通常2秒但客户端有连接复用curl -H Connection: close ...强制关闭连接在回滚后用curl -H Connection: close测试或等待客户端连接自然超时5.2 独家避坑技巧来自生产环境的3个血泪教训技巧1用“金丝雀健康检查”代替人工验证不要等QA报告“页面打不开”在VirtualService里内置健康检查# 在VS的http.route下添加 - match: - headers: x-canary-check: exact: true # 自定义Header route: - destination: host: httpbin.canary-demo.svc.cluster.local subset: v2 # 然后用curl -H x-canary-check:true ... 主动探测v2是否就绪这个技巧让我们把金丝雀启动时间从“人工点击10个页面”压缩到“1条curl命令”且可集成到CI/CD流水线。技巧2为金丝雀流量打上唯一TraceID当v2出现异常你需要快速定位是哪个金丝雀请求触发的。在VirtualService中注入TraceID- route: - destination: host: httpbin.canary-demo.svc.cluster.local subset: v2 headers: request: set: x-canary-id: canary-20240615-v2 # 固定值便于日志搜索然后在应用日志里打印x-canary-id所有v2的日志天然带上标记grep canary-20240615-v2即可捞出全部相关日志。技巧3金丝雀期间禁用自动扩缩容HPA这是最容易被忽视的坑。当v2因性能问题导致P95延迟飙升HPA会自动给v2扩容把更多流量引向劣质版本形成正反馈恶化。解决方案# 在v2的Deployment里添加注解临时禁用HPA annotations: autoscaling.alpha.kubernetes.io/behavior: {ScaleUp:{StabilizationWindowSeconds:0},ScaleDown:{StabilizationWindowSeconds:0}} # 或者更彻底金丝雀期间手动删除v2的HPA对象 kubectl delete hpa -n canary-demo httpbin-v2-hpa我亲眼见过一个案例v2版本有严重GC问题HPA在5分钟内把副本数从2扩到12结果整个集群的etcd因写入压力过大开始丢包最终引发连锁故障。从此我们所有金丝雀流程的第一步就是kubectl get hpa -n $NS | grep v2 | xargs kubectl delete hpa -n $NS。6. 进阶场景与扩展从金丝雀到全自动发布流水线6.1 基于指标的自动金丝雀Auto-Canary告别手动升权手动调整权重是初级玩法。真正的效率提升在于让系统自己判断“v2是否健康”并自动推进。这需要Istio Prometheus 自定义Operator的组合。核心思路写一个脚本每5分钟查询Prometheus如果v2的错误率0.1%且P95延迟v1的110%则自动把VirtualService中v2的权重5%。脚本框架如下#!/usr/bin/env python3 import requests import yaml from kubernetes import client, config # 1. 查询Prometheus指标 prom_url http://prometheus.istio-system.svc.cluster.local/api/v1/query query_v2_error sum(rate(istio_requests_total{destination_versionv2, response_code~5.*}[5m])) / sum(rate(istio_requests_total{destination_versionv2}[5m])) res requests.get(prom_url, params{query: query_v2_error}) v2_error_rate float(res.json()[data][result][0][value][1]) # 2. 判断是否达标 if v2_error_rate 0.001: # 0.1% # 3. 获取当前VS vs client.CustomObjectsApi().get_namespaced_custom_object( groupnetworking.istio.io, versionv1beta1, namespacecanary-demo, pluralvirtualservices, namehttpbin-vs )