找回密码
 立即注册
首页 业界区 业界 istio流量分发实战:从配置到踩坑全解析 ...

istio流量分发实战:从配置到踩坑全解析

焦尔蕾 2026-2-4 15:25:01
前言

上一小节,istio成功的安装,并且还解决了常见的426的问题,本节内容主要探讨一下istio关于流量转发的问题
按比例分发

配置

需要创建一个backend-v1,它与backend的selector都是app: backend,backend-v1部署完成之后,它会立即分走50%的流量,为了测试istio流控,我们需要在不改变任何配置的情况下实现9:1分流,也就是90%进入原backend,10%进入新的backend-v1
1.png


  • 标记2个deployment,追加标签,backend为version: v0,backend-v1为version: v1
    1. kubectl patch deployment backend -p '{"spec":{"template":{"metadata":{"labels":{"version":"v0"}}}}}'
    2. kubectl patch deployment backend-v1 -p '{"spec":{"template":{"metadata":{"labels":{"version":"v1"}}}}}'
    复制代码
  • 创建istio资源:DestinationRule,该资源主要用来标记istio要往哪个地方转发
    1. apiVersion: networking.istio.io/v1
    2. kind: DestinationRule
    3. metadata:
    4.   name: backend-dr
    5.   namespace: default
    6. spec:
    7.   host: backend-service
    8.   subsets:
    9.   - labels:
    10.       version: v0
    11.     name: v0
    12.   - labels:
    13.       version: v1
    14.     name: v1
    复制代码
  • 创建istio资源:VirtualService,该资源用来确定转发的权重
    1. apiVersion: networking.istio.io/v1
    2. kind: VirtualService
    3. metadata:
    4.   name: backend-vs
    5.   namespace: default
    6. spec:
    7.   hosts:
    8.   - backend-service
    9.   http:
    10.   - route:
    11.     - destination:
    12.         host: backend-service
    13.         subset: v0
    14.       weight: 90
    15.     - destination:
    16.         host: backend-service
    17.         subset: v1
    18.       weight: 10
    复制代码
调试


  • 测试命令: for i in {1..10}; do curl -s 10.22.12.178:30785/test > /dev/null ; done
  • 登录到k8s的istio-proxy控制台查看: kubectl logs -f -l app=backend -c istio-proxy
    1. [2026-01-28T08:24:55.670Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    2. [2026-01-28T08:24:55.687Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    3. [2026-01-28T08:24:55.706Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
    4. [2026-01-28T08:24:55.741Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default
    5. [2026-01-28T08:24:55.751Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
    6. [2026-01-28T08:24:55.759Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
    7. [2026-01-28T08:24:55.696Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    8. [2026-01-28T08:24:55.716Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    9. [2026-01-28T08:24:55.725Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    10. [2026-01-28T08:24:55.734Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
    复制代码
    1. ▶ kubectl get pod -owide
    2. NAME                          READY   STATUS    RESTARTS   AGE     IP            NODE     NOMINATED NODE   READINESS GATES
    3. backend-86b958bdc-5zjgn       2/2     Running   0          21m     10.244.0.53   wilson   <none>           <none>
    4. backend-v1-75ccff86dc-sl6bt   2/2     Running   0          119s    10.244.0.55   wilson   <none>           <none>
    5. nginx-test-7d87875694-8vsrp   2/2     Running   0          30m     10.244.0.61   wilson   <none>           <none>
    复制代码
  • 明显不对,10.244.0.55与10.244.0.53的比例并没有呈现9:1,转发到backend要backend-v1还是5:5
修复

可以直接修改nginx的配置
  1. server {
  2.     listen       80;
  3.     listen  [::]:80;
  4.     server_name  localhost;
  5.     location /test {
  6.         proxy_http_version 1.1;
  7.         # proxy_set_header Host $host; # 原配置
  8.         proxy_set_header Host backend-service.default.svc.cluster.local; # 新配置
  9.         proxy_pass http://backend-service:10000;
  10.     }
  11. }
复制代码
重启之后再次测试:
  1. [2026-01-28T08:30:59.968Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  2. [2026-01-28T08:30:59.988Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default
  3. [2026-01-28T08:31:00.027Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=1ms route=default
  4. [2026-01-28T08:31:00.037Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  5. [2026-01-28T08:31:00.048Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  6. [2026-01-28T08:31:00.056Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  7. [2026-01-28T08:31:00.008Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.55:10000 duration=0ms route=default
  8. [2026-01-28T08:31:00.066Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  9. [2026-01-28T08:31:00.074Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
  10. [2026-01-28T08:31:00.083Z] "GET /test HTTP/1.1" 200 - upstream=10.244.0.53:10000 duration=0ms route=default
复制代码
已经生效了,这次只有1次10.244.0.55:10000
疑问

有位大哥说了,如果这样配置的,明显影响了业务:

  • nginx的配置被修改了
  • 所有的host被写死了,都成了:backend-service.default.svc.cluster.local,而后端业务是需要把客户端的host带入过去的,改了之后后端业务收到严重影响
确实,固定host属于粗暴简单的写法,还有更加惊喜的解决方法,调整VirtualService,添加hosts
  1. apiVersion: networking.istio.io/v1
  2. kind: VirtualService
  3. metadata:
  4.   name: backend-vs
  5.   namespace: default
  6. spec:
  7.   hosts:
  8.   - backend-service
  9.   - api.wilsontest.com # 新增
  10.   http:
  11.   - route:
  12.     - destination:
  13.         host: backend-service
  14.         subset: v0
  15.       weight: 90
  16.     - destination:
  17.         host: backend-service
  18.         subset: v1
  19.       weight: 10
复制代码
客户端访问的时候必须带上该域名: for i in {1..10}; do curl -s -H 'host: api.wilsontest.com' 10.22.12.178:30785/test > /dev/null ; done
这样也可以解决问题,不过坑点也来了,年久失修,从无数前人继承的祖传代码,就需要好好的梳理到底有哪些host来访问,否则漏掉host的话,就会出现配置问题。-_-!
再次凸显了istio之中,host是非常非常重要的,Istio 的路由决策、Service 的匹配完全依赖 Host 头

  • Istio 的 VirtualService 本质上是一个“增强版”的路由器。如果发现请求的 Host 是 backend-service,就按 90:10 分配。
  • 之前的配置是$host,由于客户端没有传输host,当请求经过 Nginx 的 Sidecar时,它会检查Host,发现为空。由于路由表里没有对应的记录 ,sidecar并不认识,按普通 K8s 流量处理
按header分发
  1. apiVersion: networking.istio.io/v1
  2. kind: VirtualService
  3. metadata:
  4.   name: backend-vs
  5.   namespace: default
  6. spec:
  7.   hosts:
  8.   - backend-service
  9.   - api.wilsontest.com
  10.   http:
  11.   - match:
  12.     - headers:
  13.         hellotest:
  14.           exact: "true"
  15.     route:
  16.     - destination:
  17.         host: backend-service
  18.         subset: v1
  19.   - route:
  20.     - destination:
  21.         host: backend-service
  22.         subset: v0
复制代码
curl -s -H 'host: api.wilsontest.com' -H 'hellotest: true' 10.22.12.178:30785/test。只有header里面匹配了hellotest: true才会去v1,否则全部去v0
按前缀分发
  1. apiVersion: networking.istio.io/v1
  2. kind: VirtualService
  3. metadata:
  4.   name: backend-vs
  5.   namespace: default
  6. spec:
  7.   hosts:
  8.   - backend-service
  9.   - api.wilsontest.com
  10.   http:
  11.   - match:
  12.     - uri:
  13.         prefix: /test/v1
  14.     route:
  15.     - destination:
  16.         host: backend-service
  17.         subset: v1
  18.   - route:
  19.     - destination:
  20.         host: backend-service
  21.         subset: v0
复制代码
带有/test/v1前缀的都会去新版本v1,满足不了条件都会走默认的版本v0
url改写
  1. apiVersion: networking.istio.io/v1
  2. kind: VirtualService
  3. metadata:
  4.   name: backend-vs
  5.   namespace: default
  6. spec:
  7.   hosts:
  8.   - backend-service
  9.   - api.wilsontest.com
  10.   http:
  11.   - match:
  12.     - uri:
  13.         prefix: /test/v1
  14.     route:
  15.     - destination:
  16.         host: backend-service
  17.         subset: v1
  18.   - match:
  19.     - uri:
  20.         prefix: /test/v2
  21.     rewrite:
  22.       uri: /test
  23.     route:
  24.     - destination:
  25.         host: backend-service
  26.         subset: v0
  27.   - route:
  28.     - destination:
  29.         host: backend-service
  30.         subset: v0
复制代码
如果是/test/v1,就访问v1版本,/test/v2重写成/test并且访问v0版本,其余的默认都会走v0版本
蓝绿、金丝雀、灰度、A/B测试

关于流量分流的各种操作,大部分都集中在以下场景:

  • 蓝绿:实现瞬间切换与零宕机回滚,消除发布期间的中间状态
  • 金丝雀:像矿工用金丝雀探测毒气一样,先让一小部分用户(如1%~5%)访问新版本,观察系统指标(如错误率、延迟),若无问题再逐步扩大范围
  • 灰度:将用户群体按比例或特定规则(如地域、设备)逐步切换到新版本(例如10%→30%→100%),持续观察反馈
  • A/B:同时向随机分组的用户展示不同版本(A组用旧版,B组用新版),通过统计指标(如点击率、转化率)判断哪个版本更优
蓝绿发布金丝雀发布灰度发布A/B测试主要目标零停机、瞬时回滚用真实流量快速发现技术风险平稳、可控地逐步替换所有用户验证不同版本的业务效果流量路由全量切换(100%→0%)极小比例引流(如1%-5%)按比例分阶段扩大(10%→50%→100%)按规则/随机分配(如50%/50%)关注重点系统可用性与回滚速度系统稳定性指标(错误率、延迟)发布过程平稳性与综合反馈业务指标(转化率、留存率)所需资源两套完整环境,成本高一套环境,新版本实例较少一套环境,新旧版本实例共存一套或多套环境,并行运行多个版本用户选择全体用户同时切换小部分用户随机或按基础设施选择用户按比例或属性逐步迁移用户随机分组或按属性定向分配持续时间极短(切换在几分钟内)短(几小时到一天)中长(几天到数周)长(数周到数月)典型场景关键业务大版本升级、基础设施更换后端服务、中间件、数据库变更前端功能、用户界面更新UI设计、文案、算法策略、定价优化联系我


  • 联系我,做深入的交流
2.bmp

至此,本文结束
在下才疏学浅,有撒汤漏水的,请各位不吝赐教...

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

2026-2-8 23:37:51

举报

2026-2-10 07:00:43

举报

2026-2-10 17:45:32

举报

您需要登录后才可以回帖 登录 | 立即注册