服务网格Istio流量治理实践

Istio流量治理实践

1.Bookinfo项目介绍

项目介绍:https://istio.io/latest/docs/examples/bookinfo/

后面所有练习都基于该项目:

2.部署Bookinfo项目

首先在 Kubernetes 集群中,部署 Bookinfo 项目。

Istio 提供了用于测试功能的应用程序 Bookinfo,可以直接通过下述命令创建 Bookinfo:

1
2
3
4
5
6
7
8
9
10
#创建该项目的命名空间bookinfo
[root@k8s-master01 istio-1.24.3]# kubectl create ns bookinfo
namespace/bookinfo created

#使用istio管理bookinfo命名空间中的所有pod,给命名空间添加istio-injection=enabled标签,这样在bookinfo命名空间的所有pod都会被自动注入sidecar。也可以在kiali界面操作
#使用命令添加标签
[root@k8s-master01 istio-1.24.3]# kubectl label ns bookinfo istio-injection=enabled
namespace/bookinfo labeled

#在kiali控制台操作参考下图:

找到要管理的命名空间,这里是bookinfo,点击命名空间右侧的三个点,如下图:

然后再次点击Enable Auto Injection

在弹出的提示框选择Enable

看到该提示表示成功Namespace updated

验证bookinfo命名空间是否被添加istio-injection=enabled标签

1
2
3
4
[root@k8s-master01 istio-1.24.3]# kubectl get ns bookinfo --show-labels
NAME STATUS AGE LABELS
bookinfo Active 9m35s istio-injection=enabled,kubernetes.io/metadata.name=bookinfo
#可以看到LABELS列中已经有了istio-injection=enabled标签

创建项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 在下载的istio安装包中已经自带了bookinfo项目所用的资源文件,不过需要修改镜像下载地址,我已经把用到的镜像同步到了自己的仓库中。
#老规矩,在创建项目前修改yaml中的镜像下载地址,共修改6个镜像地址
文件全路径:/root/26-istio/istio-1.24.3/samples/bookinfo/platform/kube/bookinfo.yaml
修改后的内容参考如下:
[root@k8s-master01 istio-1.24.3]# cat samples/bookinfo/platform/kube/bookinfo.yaml |grep image
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-details-v1:1.20.2
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-ratings-v1:1.20.2
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-reviews-v1:1.20.2
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-reviews-v2:1.20.2
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-reviews-v3:1.20.2
imagePullPolicy: IfNotPresent
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/examples-bookinfo-productpage-v1:1.20.2
imagePullPolicy: IfNotPresent

修改后开始创建bookinfo项目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#使用-n参数 指定创建到bookinfo命名空间中
[root@k8s-master01 istio-1.24.3]# kubectl create -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo
service/details created
serviceaccount/bookinfo-details created
deployment.apps/details-v1 created
service/ratings created
serviceaccount/bookinfo-ratings created
deployment.apps/ratings-v1 created
service/reviews created
serviceaccount/bookinfo-reviews created
deployment.apps/reviews-v1 created
deployment.apps/reviews-v2 created
deployment.apps/reviews-v3 created
service/productpage created
serviceaccount/bookinfo-productpage created
deployment.apps/productpage-v1 created

查看pod和Service情况:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# pod
[root@k8s-master01 istio-1.24.3]# kubectl get po -n bookinfo
NAME READY STATUS RESTARTS AGE
details-v1-5655bbb7bb-l8wkq 2/2 Running 0 77s
productpage-v1-7f86d94f89-nkxnz 2/2 Running 0 76s
ratings-v1-6dccb8487d-fn74n 2/2 Running 0 77s
reviews-v1-5c8cf97b4d-npnqq 2/2 Running 0 76s
reviews-v2-7685b9f4f4-md5v9 2/2 Running 0 76s
reviews-v3-846946d6cb-l98z2 2/2 Running 0 76s

# svc
[root@k8s-master01 ~]# kubectl get svc -n bookinfo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.96.79.2 <none> 9080/TCP 4m44s
productpage ClusterIP 10.96.113.166 <none> 9080/TCP 4m43s
ratings ClusterIP 10.96.151.91 <none> 9080/TCP 4m44s
reviews ClusterIP 10.96.224.30 <none> 9080/TCP 4m44s

将名字是productpage的Service类型改为NodePort,来访问项目:

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master01 ~]# kubectl edit  svc -n bookinfo  productpage
# 找到type: ClusterIP,并修改为NodePort类型
type: NodePort

# 接下来可以通过30963端口访问项目
[root@k8s-master01 ~]# kubectl get svc -n bookinfo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.96.79.2 <none> 9080/TCP 14m
productpage NodePort 10.96.113.166 <none> 9080:30963/TCP 14m
ratings ClusterIP 10.96.151.91 <none> 9080/TCP 14m
reviews ClusterIP 10.96.224.30 <none> 9080/TCP 14m

3.Istio IngressGateway对外发布服务

测试可以使用NodePort类型的service进行访问,正式环境都是通过域名进行访问,这里着重讲解域名的方式,以bookinfo.ibstd.com域名为例:

整体流程如下:

①:配置DNS解析:将 bookinfo.ibstd.com 解析到 Istio Ingress Gateway 的外部 IP 地址(我本地测试通过修改hosts实现)。

②:配置 Istio Gateway:创建一个 Istio Gateway 资源,用于配置域名、端口和协议(HTTP 或 HTTPS)。Gateway 负责管理进入 Istio 服务网格的流量。

③:配置 Istio VirtualService:创建一个 Istio VirtualService 资源,将 Gateway 中定义的流量路由到 Bookinfo 的 productpage 服务。VirtualService 定义了路由规则。

④:测试访问:验证通过域名 bookinfo.ibstd.com 是否能够成功访问 Bookinfo 项目

具体操作参考下面步骤:

3.1配置DNS解析

将 bookinfo.ibstd.com 域名解析到Istio 的Ingress Gateway pod所在ip上,因为我测试环境配置的Ingress Gateway的Service类型是NodePort,本地 hosts 文件解析是将 bookinfo.ibstd.com 解析 任意一个Kubernetes 节点的 IP。

1
2
3
#配置如下:找到hosts文件添加192.168.0.81 bookinfo.ibstd.com
#windwos的路径是:C:\Windows\System32\drivers\etc\hosts
#centos7路径是:/etc/hosts

k8s节点IP如下:

3.2创建Gateway资源

在 Istio 中,Gateway 资源用于管理进入(Ingress)和离开(Egress)的流量。具体来说,Ingress Gateway 负责接收来自外部的请求,并根据配置的路由规则将流量转发到相应的服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#gateway资源配置解读:
# ==================== 1. Gateway:定义 Istio 网关的监听规则 ====================
apiVersion: networking.istio.io/v1 # API 版本:表示使用 Istio 网络管理 API 的 v1 版本;集群必须已安装对应的 CRD
kind: Gateway # 资源类型:Istio Gateway,负责配置入口网关的端口、协议和允许访问的主机名
metadata: # 定义资源元数据:描述这个 Gateway 资源本身
name: bookinfo-gateway #定义Gateway 资源的名称。名为 bookinfo-gateway,供 VirtualService.spec.gateways 引用;同一命名空间内必须唯一。
spec: # Gateway 的实际配置内容
selector: #标签选择器,指定由哪些网关 Pod 接收这份 Gateway 配置。
istio: ingressgateway # Pod 标签选择条件:选择带有 istio=ingressgateway 标签的工作负载处理流量,也就是说istio-ingressgateway的pod必须有istio=ingressgateway标签
servers: # 网关监听规则列表:一个 Gateway 可以配置多个监听端口或协议
- port: # 当前这条监听规则的端口配置
number: 80 #告诉 Envoy:“对于所有从 80 端口进来的流量,请按照我定义的规则(比如 host 是 bookinfo.ibstd.com)来处理。” 这里定义的端口号要和名字是istio-ingressgateway的Service的port字段保持一致。
name: http #为端口命名,便于在同一个 Gateway 中区分不同的端口和协议。名称应具有描述性唯一性,如 http、https 等。
protocol: HTTP # 监听协议:告诉 Istio 按 HTTP 协议处理进入网关的流量,要与 VirtualService.spec.http 的 HTTP 路由规则相对应
hosts: # 定义哪些主机名的请求将由此 Gateway 处理,允许处理的主机列表。必须与下面 VirtualService.spec.hosts 对应
- "bookinfo.ibstd.com" #定义bookinfo.ibstd.com的请求由此Gateway处理。可以根据需要添加多个主机名。

---
# ==================== 2. VirtualService:定义请求匹配及转发规则 ====================
apiVersion: networking.istio.io/v1 #指定api的版本
kind: VirtualService #定义创建资源的类型
metadata: # # VirtualService 自身的元数据
name: bookinfo # VirtualService资源的名字
spec: # 定义VirtualService 的实际配置内容,流量路由配置
hosts: #这条路由规则适用于哪些目标主机
- "bookinfo.ibstd.com" #应与 Gateway.spec.servers[].hosts 中允许的主机名匹配,这里定义的主机必须要被关联的Gateway.spec.servers.port[].host的值匹配到
gateways: # 指定哪些 Gateway 使用这套路由规则,与gateway资源关联
- bookinfo-gateway # 引用上述名字是 bookinfo-gateway 的 Istio Gateway 资源
# 如果VirtualService和Gateway在同一个空间,那直接写名字
# 如果 Gateway 位于 istio-system,而 VirtualService 位于 default
# 则要加上命名空间,写成 istio-system/bookinfo-gateway
http: # HTTP 路由规则列表:定义如何匹配 HTTP 请求及转发请求
- match: # 当前路由规则的匹配条件列表 # 下面的多个 match 条目之间是 OR(或)关系:只要任意一个条 目匹配,就可以执行当前 route
- uri: # 第一个匹配条件:检查请求 URI 路径
exact: /productpage # 精确匹配 /productpage,例如 /productpage 匹配,但 /productpage/ 不匹配
- uri: # 第二个匹配条件
prefix: /static # 前缀匹配 /static 开头的路径,例如 /static/a.css 可以匹配
- uri: # 第三个匹配条件
exact: /login # 精确匹配,, /login匹配 , /login/不匹配
- uri: ## 第四个匹配条件
exact: /logout #精确匹配 /logout
- uri: # 第五个匹配条件
prefix: /api/v1/products # 前缀匹配 /api/v1/products 开头的路径,例如 /api/v1/products 和 /api/v1/products/1 均可匹配
route: # 路由动作,指定上述路由规则匹配成功后的请求要转发到给谁处理
- destination: # 当前转发目标;route 是列表,可以配置一个或多个目标
host: productpage # 后端目标 Service 的名称,如果 Service 在其他命名空间,应使用完整名称,例如:productpage.bookinfo.svc.cluster.local
port: # 后端目标服务的端口配置
number: 9080 # 目标 Service 端口号,应与 productpage Kubernetes Service 的 spec.ports[].port的值一致

3.3创建VirtualService

VirtualService将网关接收的外部流量请求 路由到Kubernetes集群内的具体服务,实现了精确的流量控制。

VirtualService与Gateway资源协同工作:Gateway定义了进入网格的入口点,而VirtualService则定义了如何将进入的流量精确路由到集群内的各个服务。这种分离使得流量管理更加灵活和可配置。

总的来说,VirtualService在Istio服务网格中扮演”交通指挥官”的角色,确保外部访问请求被正确地导向集群内的目标服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: bookinfo-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.ibstd.com"
---
#VirtualService资源配置解析
apiVersion: networking.istio.io/v1 #指定了 Kubernetes API 的版本
kind: VirtualService #指定资源的类型是VirtualService。VirtualService 用于配置如何在服务网格内部路由和处理请求。
metadata: #定义资源的元数据
name: bookinfo #定义这个vs资源的名称,这里是bookinfo
spec: #定义 VirtualService 的具体规格或配置。
hosts: #指定 VirtualService 要处理的目标主机
- "bookinfo.ibstd.com" #与上述 Gateway 中的 hosts 字段中的值匹配,也就是说只有请求的地址是bookinfo.ibstd.com时才会执行本vs规则中的定义的URL匹配和转发
gateways: #Gateway 接受请求后,Envoy 开始查找关联的 VirtualService
- bookinfo-gateway #这里指定的是要绑定的Gateway资源的名字,把vs资源的路由逻辑(URI、权重、转发地址),挂载 Gateway 监听器上。
http: #定义了 HTTP 路由规则。可以定义多个路由规则。
- match: #定义了请求匹配条件。当请求满足所有匹配条件时,将应用对应的路由规则。
- uri: #
exact: /productpage #匹配 URI 精确为 /productpage 的请求。
- uri:
prefix: /static #匹配 URI 以 /static 为前缀的请求,通常用于静态资源。
- uri:
exact: /login #匹配 URI 精确为 /login 的请求。
- uri:
exact: /logout # 匹配 URI 精确为 /logout 的请求
- uri:
prefix: /api/v1/products # 匹配 URI 以 /api/v1/products 为前缀的请求,通常用于产品 API 接口。
route: #定义了匹配请求的路由目标
- destination: #指定请求的目标地址。
host: productpage #指定目标服务的主机名为 productpage。在 Istio 服务网格中,服务通常通过其 Kubernetes Service Name 来引用。这里 productpage 是一个 Kubernetes Service 的名称。
port: #指定目标服务的端口。
number: 9080 #指定目标服务的端口号为 9080


#下面是bookinfo项目的service信息:
[root@k8s-master01 istio-1.24.3]# kubectl get svc -n bookinfo
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.96.76.76 <none> 9080/TCP 2d16h
productpage ClusterIP 10.96.60.175 <none> 9080/TCP 2d16h
ratings ClusterIP 10.96.99.140 <none> 9080/TCP 2d16h
reviews ClusterIP 10.96.210.82 <none> 9080/TCP 2d16h

3.4测试访问

在本地hosts文件中添加一条解析:

1
2
#windwos的路径是:C:\Windows\System32\drivers\etc\hosts
#在文件最后新增一行192.168.0.81 bookinfo.ibstd.com

在浏览器输入bookinfo.ibstd.com:32662/productpage,可以看到服务可以正常访问。

这里的32662是istio-ingressgateway的service对外暴露的端口号:

多次刷新可以看到 Reviewer 处的星星会在黑色、红色和消失之间来回替换,是因为之前部署了三个不同版本的 reviews,每个版本具有不同的显示效果。

此时通过 Kiali 页面可以看到 Bookinfo 的调用链路:

3.5配置HTTPS访问

为bookinfo站点配置https证书。

首先生成证书,这里我测试用的自签名证书,在正式环境要购买证书。

1
2
3
4
5
6
7
8
9
[root@k8s-master01 26-istio]# openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout istiotls.key -out istiotls.crt -subj "/CN=bookinfo.ibstd.com"
........+.....+.+..............+....+..+....+...+++++++++++++++++++++++++++++++++++++++*....+........+...+....+++++++++++++++++++++++++++++++++++++++*...+...+......+............................+......+.....+......................+..+..........+..+...+.......+.....+.+...+...........+.+..+...+....+...+.....++++++
..+......+.+........+.......+.....+..........+.....+.........+......+....+........+...+..........+..+.+.....+....+......+.....+............+....+++++++++++++++++++++++++++++++++++++++*.+++++++++++++++++++++++++++++++++++++++*...+.+..+...+...+......+.+........+..........+...............+......++++++
-----

# 生成的证书文件
[root@k8s-master01 26-istio]# ll istiotls.*
-rw-r--r-- 1 root root 1139 Nov 5 14:23 istiotls.crt
-rw------- 1 root root 1704 Nov 5 14:23 istiotls.key

接下来利用证书文件创建一个tls类型的Secret:

1
2
# 创建一个tls类型的Secret,创建的Secret要和istio-ingressgateway的pod在同一个命名空间,不要把Secret创建在微服务项目所在的空间,例如bookinfo
[root@k8s-master01 26-istio]# kubectl create secret tls bookinfo-tls --cert=istiotls.crt --key=istiotls.key -n istio-system

最后修改gateway资源增加证书的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 增加两端tls的配置即可
[root@k8s-master01 26-istio]# kubectl edit gateways.networking.istio.io -n bookinfo bookinfo-gateway
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
creationTimestamp: "2026-10-28T08:49:12Z"
generation: 5
name: bookinfo-gateway
namespace: bookinfo
resourceVersion: "106214448"
uid: de60baba-6d14-4aa3-badc-b6ebb7b58864
spec:
selector:
istio: ingressgateway
servers:
# 第一个 Server 块:处理 80 端口的 HTTP 流量
- hosts:
- bookinfo.ibstd.com # 匹配的域名
port:
name: http
number: 80 # 监听 80 端口
protocol: HTTP
tls:
# 【第一个 TLS 配置:HTTP 重定向】
# 这里的 tls 并不是用来配置证书的,而是用来控制 HTTP 流量的跳转行为。
# httpsRedirect: true 意味着当用户访问 http://bookinfo.ibstd.com 时,
# Istio 网关会直接返回 HTTP 301 状态码,强制浏览器跳转到 443 端口的 HTTPS 地址。
# 适用场景:你希望所有流量都安全加密,不允许明文 HTTP 访问时开启。
httpsRedirect: true

# 第二个 Server 块:处理 443 端口的 HTTPS 流量
- hosts:
- bookinfo.ibstd.com # 匹配相同的域名
port:
name: https
number: 443 # 监听 443 端口
protocol: HTTPS
tls:
# 【第二个 TLS 配置:HTTPS 证书与模式】
# 这里是真正的 TLS (SSL) 证书配置,用于在网关层卸载(解密)HTTPS 流量。
# mode: SIMPLE
# 指定 TLS 连接的模式。SIMPLE 代表“标准的单向 TLS 认证”。
# 就像我们日常访问普通的 HTTPS 网站一样,只有服务端(网关)向客户端(浏览器)提供证书来证明身份。
# 其他可选值:
# - MUTUAL:双向 TLS (mTLS),不仅服务端要提供证书,客户端也要提供证书(常用于对内网或高安全 API)。
# - PASSTHROUGH:透传模式,网关不解密流量,直接把加密流量原封不动地转发给后端的 Pod 解密。
mode: SIMPLE

# credentialName: bookinfo-tls
# 指定包含 TLS 证书的 Kubernetes Secret 的名称。
# Istio 会去读取这个名为 `bookinfo-tls` 的 Secret(通常包含 tls.crt 公钥和 tls.key 私钥),
# 将其加载到 Envoy 代理中,用来为 `bookinfo.ibstd.com` 这个域名提供 HTTPS 加密。
# 注意:通常情况下,这个 Secret 需要和 Istio Ingress Gateway 的 Pod 在同一个命名空间(默认是 istio-system)。
credentialName: bookinfo-tls

web端访问测试:

3.6总结

用户从外部请求 http://bookinfo.ibstd.com:32662/productpage:

  1. 到达 Kubernetes 集群节点的 32662 端口 (NodePort)。
  2. 转发到 istio-ingressgateway Service 的 80端口。
  3. Service 将请求转发到 istio-ingressgateway-xxx Pod 的 8080端口。
  4. Pod 中的 istio-proxy 容器代理组件接收请求,根据请求的 Host 头部和到达Service的端口(80)查找匹配的 Gateway 资源。
  5. 如果找到匹配的 Gateway,istio-proxy 应用该 Gateway 的配置。
  6. istio-proxy 根据请求的 URL 路径和 VirtualService 的配置,将请求路由到 productpage 服务。在VirtualService中有个spec.gateways字段,该字段配置的是提前创建的Gateway资源的名字(metadata.name),它是一个字符串列表。这个列表明确指定了哪些 Gateway 的配置应该与此 VirtualService 关联。
  7. productpage Service 将请求负载均衡到后端的 productpage Pod。
  8. productpage Pod处理请求

4.Istio中域名重定向和地址重写

🔑 核心区别

维度 Redirect (重定向) Rewrite (重写)
行为方 客户端(浏览器) 服务端(Istio/Envoy)
HTTP 状态码 301 / 302 / 307 / 308 无(对客户端透明)
浏览器地址栏 ✅ 会变化 ❌ 不变
请求次数 2次(原请求 + 新请求) 1次(内部改写后直接转发)
客户端感知 完全感知 完全无感
配置字段 redirect rewrite

💡 一句话总结:Redirect 是告诉客户端”你去别的地方找”;Rewrite 是服务端自己”偷偷改个地址再帮你找”。

4.1域名重定向(Redirect)

案例场景:旧域名迁移到新域名,要求浏览器输入bookinfo.ibstd.com:32662/baidu 跳转到www.baidu.com

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# 这里还是使用上述 3.2 和 3.3 中创建的资源演示
[root@k8s-master01 ~]# kubectl get vs -n bookinfo
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["bookinfo.ibstd.com"] 45h

# 修改VirtualService资源
[root@k8s-master01 ~]# kubectl edit vs -n bookinfo bookinfo
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
creationTimestamp: "2026-10-28T08:49:12Z"
generation: 9
name: bookinfo
namespace: bookinfo
resourceVersion: "103986394"
uid: 6b56885b-74c4-4583-a122-65e491b97fa4
spec:
gateways:
- bookinfo-gateway
hosts:
- bookinfo.ibstd.com
http:
- match: #用于定义路由规则的触发条件
- uri: #uri 用于匹配 HTTP 请求路径(Path)
prefix: /baidu # prefix 表示“前缀匹配”:只要请求路径以指定字符串开头即视为命中
# 命中示例:/baidu、/baidu/、/baidu/news、/baidu/search?q=k8s
# 未命中示例:/other/baidu、/bai
redirect: # 当请求命中上述 match 条件时,执行重定向动作
authority: www.baidu.com #将请求的主机头(Host/Authority)修改为指定的www.baidu.com域名
uri: / # 显式覆盖重定向的目标路径为根路径 "/"(丢弃客户端后续的子路径)
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080

在浏览器输入bookinfo.ibstd.com:30080/baidu,回车观察地址变化

浏览器会自动跳转到www.baidu.com

在VirtualService中不同的http写法,作用是不一样的:

写法一:全站域名迁移 / 协议强制升级(通配兜底)

1
2
3
4
5
http:
- redirect:
scheme: https
authority: www.example.com
redirectCode: 301

含义:

  • **省略 match**:代表默认通配规则(Match All)。只要访问匹配到该 VirtualService 的 hosts,无论是根路径、具体文章还是 API 请求,都会无条件触发该规则。

  • **未配置 uri**:Envoy 只会替换协议为 https、域名为 [www.example.com](https://www.example.com),原请求的路径(Path)和查询字符串(Query)被完整透传。

路径效果:

1
2
原请求地址:http://old.example.com/api/v1?id=5
重定向后的地址:https://www.example.com/api/v1?id=5

适用场景:全站换域名、HTTP 强跳 HTTPS、老域名整体 301 永久废弃迁移。

写法二:局部路由重定向并收敛到根目录(截断路径)

1
2
3
4
5
6
7
http:
- match:
- uri:
prefix: /baidu
redirect:
authority: www.baidu.com
uri: /

含义:

  • **有 match**:仅拦截前缀为 /baidu 的请求,其他非 /baidu 开头的请求不会触发,会继续向下流转给后续规则。
  • **显式配置 uri: /:无论原请求在 /baidu 后面拼接了什么子路径或参数,重定向后的路径都会被强制替换(Override)为根路径 /**。

路径效果:

1
2
原请求地址:http://old.example.com/baidu/news?id=5
重定向后的地址:http://www.baidu.com/

适用场景:外部快捷入口重定向(如用户访问当前站点的某个别名目录 /baidu、/docs,统一导向外部目标站点的首页)。

写法三:局部路由重定向且保持原路径透传(保留子路径)

1
2
3
4
5
6
http:
- match:
- uri:
prefix: /baidu
redirect:
authority: www.baidu.com

含义:

  • **有 match**:同样仅拦截前缀为 /baidu 的请求。
  • 未配置 uri:由于没有指定具体的重写路径,Envoy 会仅将 Host 改为 [www.baidu.com](https://www.baidu.com),同时完整保留客户端原本请求的全部路径(包含前缀 /baidu)与查询参数。

路径效果:

1
2
原请求地址:http://old.example.com/baidu/news?id=5
重定向后的地址:http://www.baidu.com/baidu/news?id=5

适用场景:特定子目录业务平移,且目标站点上保留了完全相同的目录结构(例如目标站也有 /baidu/* 相关服务)。

对比总结:

配置写法 匹配范围 目标路径处理 示例原请求 重定向后的完整目标地址
写法 1 无 match 无 uri 全站所有请求(无条件生效) 完整保留原 Path 与 Query 参数 [http://old.example.com/api/v1?id=5] [https://www.example.com/api/v1?id=5]
写法 2 prefix: /baidu uri: / 仅以 /baidu 开头的请求 **强制覆盖为根路径 /**(丢弃子路径) [http://old.example.com/baidu/news?id=5] [http://www.baidu.com/]
写法 3 prefix: /baidu 无 uri 仅以 /baidu 开头的请求 完整保留原 Path(包含 /baidu 及后续路径)与 Query 参数 [http://old.example.com/baidu/news?id=5] [http://www.baidu.com/baidu/news?id=5]

4.2地址重写(Rewrite)

在 Istio 中,可以通过 VirtualService(VS)的 rewrite 字段实现 URL 重写(URL Rewrite)。

URL 重写的核心作用是:客户端访问的 URL 保持不变,但 Istio 在将请求转发给后端服务之前,修改 HTTP 请求的 URI。

还是在3.2和3.3创建的资源中实验,要求访问bookinfo.ibstd.com:30080显示的是bookinfo项目的页面/productpage页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
[root@k8s-master01 ~]# kubectl edit vs -n bookinfo bookinfo
# Please edit the object below. Lines beginning with a '#' will be ignored,
# and an empty file will abort the edit. If an error occurs while saving this file will be
# reopened with the relevant failures.
#
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
creationTimestamp: "2026-10-28T08:49:12Z"
generation: 10
name: bookinfo
namespace: bookinfo
resourceVersion: "104332954"
uid: 6b56885b-74c4-4583-a122-65e491b97fa4
spec:
gateways:
- bookinfo-gateway
hosts:
- bookinfo.ibstd.com
http:
- match: # 流量匹配条件列表:请求必须满足以下条件才触发后续动作
- uri:
exact: / # exact 表示“完全精确匹配”
# 命中示例:http://bookinfo.ibstd.com/、http://bookinfo.ibstd.com/?a=1(Query 参数会被保留)
#未命中示例:http://bookinfo.ibstd.com/productpage、http://bookinfo.ibstd.com/api
rewrite: # 将命中上述匹配条件的请求路径重写为rui指定的值
uri: /productpage #客户端浏览器的地址栏不会改变,仅在转发给后端 Pod 时修改 HTTP 报文中的 Path
route: # 流量转发目标
- destination: #
host: productpage #指定后端服务的Service名字,如果不在同一个命名空间要写全地址,如:productpagee.default.svc.cluster.local
port: # 后端 Service 暴露的服务端口
number: 9080
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage
port:
number: 9080

在浏览器地址栏输入:bookinfo.ibstd.com:30080,可以看到不在像之前那样还要输入后缀/productpage,因为在内部已经将url重写为/productpage,只是在浏览器端用户是无感知的

在 Istio 的 VirtualService 中,URL 重写(rewrite.uri)的核心运行法则是:**rewrite.uri 只用来替换在 match.uri 中被命中消耗的那一部分路径,未被命中的右侧子路径及查询参数会原样追加保留**。

下面将生产中最常见的配置模式、运行逻辑及地址变化完整汇总如下:

模式分类 典型场景 match.uri 配置 rewrite.uri 配置 客户端原始请求 重写后发往后端的实际请求 核心行为特征
场景 1 前缀剥离 (网关统一入口,后端服务仅监听根目录) prefix: /api uri: / GET /api/v1/users GET /v1/users 砍掉暴露给外网的路由前缀,保留业务层级与版本路径
场景 2 前缀替换 (服务名映射转换) prefix: /service-a uri: /backend-core GET /service-a/items/123 GET /backend-core/items/123 仅把 /service-a 换成 /backend-core,保留后续的 /items/123
场景 3 静态默认首页映射 (根路径转发到特定服务首页) exact: / uri: /productpage GET / GET /productpage 全量绝对覆盖,精准替换单点路径,不影响其他接口
场景 4 单点绝对映射 (单点短路径映射为完整后台路由) exact: /login uri: /auth/v2/login GET /login GET /auth/v2/login 精确匹配,仅此一个 URL 触发整体重写,带子路径(如 /login/oauth)直接不命中
场景 5 查询参数(Query String)透传 prefix: /search uri: /api/search GET /search/all?q=istio&page=1 GET /api/search/all?q=istio&page=1 rewrite.uri 仅作用于 Path,查询参数始终完整保留

5.Istio实现灰度发布

灰度发布采用渐进式推进模式。它在保留老版本(V1)的同时,先引入少量新版本(V2)实例,只将小部分流量引入新版本进行真实生产验证,随着稳定性得到验证再逐步扩大比例,直到流量全部切换到V2。

这里的案例还是用boojinfo项目演示:

1
2
3
4
5
6
7
8
9
10
11
# 服务的所有pod都已经部署好了,reviews服务有三个不同的版本,分别是v1,v2,v3
[root@k8s-master01 ~]# kubectl get po -n bookinfo
NAME READY STATUS RESTARTS AGE
details-v1-5655bbb7bb-98zbx 2/2 Running 2 (9m19s ago) 5d1h
productpage-v1-7f86d94f89-6p28z 2/2 Running 2 (9m19s ago) 5d1h
ratings-v1-6dccb8487d-q2cgd 2/2 Running 2 (9m18s ago) 5d1h
reviews-v1-5c8cf97b4d-xnvhd 2/2 Running 2 (9m2s ago) 5d1h
reviews-v2-7685b9f4f4-4g7b2 2/2 Running 2 (9m19s ago) 5d1h
reviews-v3-846946d6cb-k9x7m 2/2 Running 2 (9m18s ago) 5d1h


针对不同版本,reviews服务的pod 都有一个版本的标签,例如version=v1


使用 Istio 进行细粒度的流量管理,需要使用 DestinationRule 资源对不同标签的 Pod 划分版本。

首先创建一个 DestinationRule 资源 将 reviews 服务分成三个版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@k8s-master01 26-istio]# cat reviews-dr.yaml
apiVersion: networking.istio.io/v1 #指定该资源使用的 Istio API 版本。
kind: DestinationRule #资源类型,表示创建的资源是DestinationRule
metadata: #定义资源元数据,用于描述资源的身份和附加信息。
name: reviews-dr #定义该 DestinationRule 资源的名称(在同一个命名空间内必须唯一),自定义。
spec: #定义 DestinationRule 的核心配置部分,定义对目标服务的流量策略和子集。
host: reviews #这里定义的是Service的名字,是整个 DestinationRule 的核心字段,告诉 Istio 这个规则作用于哪个SVC服务。如果DR和svc不在同一个命名空间要写全路径,如reviews.default.svc.cluster.local
subsets: #定义服务的“子集”(版本集合)。这是灰度发布的核心。每个子集通过pod的 labels 匹配一组具有相同标签的 Pod(端点)。
- name: v1 #定义该自己的名字,通一个DR中唯一
labels: #用于筛选属于该子集的 Pod 的标签选择器。
version: v1 #这里的version: v1是pod的标签,Istio会把具有这些标签的 Pod 归入这个子集。
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3

创建DestinationRule资源:

1
2
3
# -n 指定资源创建在bookinfo这个命名空间中
[root@k8s-master01 26-istio]# kubectl create -f reviews-dr.yaml -n bookinfo
destinationrule.networking.istio.io/reviews-dr created

查看创建的资源:

1
2
3
[root@k8s-master01 26-istio]# kubectl get dr -n bookinfo
NAME HOST AGE
reviews-dr reviews 54s

此时只是创建了 DestinationRule,并没有做任何限制,所以通过浏览器访问该服务时,并没 有什么变化。但是 Kiali 中可以看到 reviews 变成了三个版本:

接下来创建 VirtualService 资源将所有访问 reviews 服务的流量指向 reviews 的 v1 版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#声明该资源遵循的 Istio 网络 API 版本。v1 为稳定版 API。
apiVersion: networking.istio.io/v1
# 定义咨资源的类型,声明创建一个 VirtualService(虚拟服务),用于定义流量进入网格后的路由分发规则。
kind: VirtualService

metadata: #定义资源的元数据信息
name: reviews-vs # 定义该 VirtualService 在当前命名空间下的名称,自定义。
# 生产建议与被治理的目标服务同名,便于管理和排查。

spec: # 定义 VirtualService 的具体配置信息
hosts: #路由规则生效的流量目标主机(Host / Authority),告诉 Envoy“只要客户端请求的目标域名/服务名是 reviews,就由本规则接管”。
- reviews #需要与 Kubernetes Service 的服务名称对应,如果SVC和vs不在同一个命名空间需要写全名reviews.bookinfo.svc.cluster.local

http: #七层(HTTP/HTTPS/gRPC)路由规则列表
- route: #路由转发动作定义,定义具体把流量导向哪一个目的地。多个 route 可用于配置权重拆分(如金丝雀发布)。

- destination: # 指定流量最终转发到哪里,固定字段
host: reviews #将流量转到到名字是reviews 的 Service上
#在常规的服务网格内部调用(东西向流量)和同服务灰度发布场景下,这里host定义的值通常和spec.host定义的值一致。

subset: v1 # 目标版本子集(Subset),v1是DestinationRule 的 spec.subsets[*].name的值,该名称必须提前在 DestinationRule声明
# 作用:强制将流量限定在特定版本的 Pod 实例池中(此处固定为 v1)。
# 若没有该 subset,Envoy 无法匹配到可用端点,会直接返回 503 异常。

不带注释的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@k8s-master01 26-istio]# cat virtualService-all-v1.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-vs
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1

创建该vs资源:

1
2
3
4
5
6
[root@k8s-master01 26-istio]# kubectl create -f virtualService-all-v1.yaml -n bookinfo
virtualservice.networking.istio.io/reviews-vs created
[root@k8s-master01 26-istio]# kubectl get vs -n bookinfo
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["bookinfo.ibstd.com"] 4d21h
reviews-vs ["reviews"] 46s

访问bookinfo项目,并在kiali的web端观察其流量走向,可以看到,流量只有到reviews的v1版本,并没有v2和v3,v1版本也不调用Ratings服务:

上述示例流量走向总结:

productpage 代码里写的 http://reviews:9080,reviews字段是reviews服务的Service的名字,表面上是在请求 Kubernetes Service,但因为productpage的 Pod 里注入了 Istio Sidecar(Envoy),这个请求根本不会直接走 Kubernetes 的 Service 负载均衡,而是被 Sidecar 拦截后,交给 Istio 的流量规则(VirtualService + DestinationRule)来处理。

详细拆解如下:

1
2
3
4
5
6
7
8
1. productpage服务的业务代码执行请求reviews服务:
GET http://reviews:9080

#这里的 reviews 确实是 Kubernetes Service 的名字。
2. 请求从 productpage 容器发出

3. 请求被 productpage 的 Sidecar(Envoy)拦截
(iptables 或 eBPF 把流量强制导向 Sidecar)

关键点来了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
4. Sidecar 看到目标是 reviews:9080 后,不会直接去问 Kubernetes “reviews 这个 Service 有哪些 Endpoints”
而是先问自己:
“针对 host = reviews,有没有对应的 VirtualService 规则?”
如果有 VirtualService,就严格按照 VirtualService 的 route 规则走。
如果没有 VirtualService,才会退化成默认行为(相当于把流量打到该 Service 的所有 Endpoints,类似 kube-proxy)。

这里我们创建了相应的VirtualService资源:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-vs
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews #这里的reviews有两个意思,①表示svc的名字,同时也会和DR资源关联
subset: v1


5. 找到 VirtualService 后:
VirtualService 说:请把流量打到 subset: v1

6. Sidecar 再去查 DestinationRule:
“reviews 的 v1 子集对应哪些 Pod?”
→ 根据 labels: version: v1 找到对应的 Pod IP

# DestinationRule资源配置如下:
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews-dr
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
- name: v3
labels:
version: v3

# VirtualService
destination:
host: reviews # ← vs的这个值必须和dr的spec.host的值匹配

# DestinationRule
spec:
host: reviews # ← dr中spec.host的值必须和上面vs中destination.host一致
# VirtualService 里的 destination.host 和 DestinationRule 里的 spec.host 必须指向同一个服务(值要一致),Istio 才能把它们正确关联起来。

7. 根据DR中划分的子级最终直接把请求发送到具体的 Pod IP(不再经过 kube-proxy)

假如有新版本上线,不想让新版本直接接入所有流量,可以使用 VirtualService 控制流量分配比例, 比如将 20%的流量路由到 v2 版本,其余的流量依旧路由到 v1 版本:

weight 字段用于按权重分配流量,是实现灰度发布(金丝雀发布)最常用的方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 在上述案例中我将左右流量全部路由到V1版本,现在需要将20%流量路由到新上的V2版,修改之前创建的VirtualService资源

# 在vs中添加 weight 字段,实现按权重分配流量
[root@k8s-master01 26-istio]# kubectl edit vs -n bookinfo reviews-vs
1 # Please edit the object below. Lines beginning with a '#' will be ignored,
2 # and an empty file will abort the edit. If an error occurs while saving this file will be
3 # reopened with the relevant failures.
4 #
5 apiVersion: networking.istio.io/v1
6 kind: VirtualService
7 metadata:
8 creationTimestamp: "2026-11-02T06:03:22Z"
9 generation: 1
10 name: reviews-vs
11 namespace: bookinfo
12 resourceVersion: "104676539"
13 uid: 64f1f82a-691d-43ea-a094-ba25bcd63067
14 spec:
15 hosts:
16 - reviews
17 http:
18 - route:
19 - destination:
20 host: reviews
21 subset: v1
22 weight: 80 #通过配置weight字段来定义流量的权重
23 - destination:
24 host: reviews
25 subset: v2
26 weight: 20

weight 字段详细说明:

项目 说明
含义 该路由目标占总流量的比例
取值范围 0 ~ 100 的整数
计算方式 所有 weight 的总和应该等于 100(Istio 会按比例分配)
是否必填 当有多个 destination 时建议填写;只有一个 destination 时可省略(默认 100%)

接下来通过浏览器端访问bookinfo项目,观察其页面显示的内容,同时在kiali观察其流量的比例:

理想情况下是在没有星星和有黑色星星切换,没有星星显示的频率高,kiali观察其v1和v2的流量比例大概为2:8,同时v2版本的reviews服务还会调用ratings服务

当新版本经过测试没有问题后,可以将流量全部切到v2版本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 修改vs资源,把流量全部切到V2版本, 可以直接删除19行到22行,也可以把v1的权重设为0,v2的权重设为100
[root@k8s-master01 26-istio]# kubectl edit vs -n bookinfo reviews-vs
1 # Please edit the object below. Lines beginning with a '#' will be ignored,
2 # and an empty file will abort the edit. If an error occurs while saving this file will be
3 # reopened with the relevant failures.
4 #
5 apiVersion: networking.istio.io/v1
6 kind: VirtualService
7 metadata:
8 creationTimestamp: "2026-11-02T06:03:22Z"
9 generation: 2
10 name: reviews-vs
11 namespace: bookinfo
12 resourceVersion: "104726003"
13 uid: 64f1f82a-691d-43ea-a094-ba25bcd63067
14 spec:
15 hosts:
16 - reviews
17 http:
18 - route:
19 - destination: #可以直接删除19行到22行
20 host: reviews
21 subset: v1
22 weight: 0
23 - destination:
24 host: reviews
25 subset: v2
26 weight: 100

再次通过浏览器访问并观察kiali调用链,此时页面只会显示有黑色星星,kiali调用链中也不会再有reviews的v1:

6.Istio实现AB测试

基于条件的流量分配

与简单的权重分流(Canary)不同,AB 测试通常根据请求的特定条件(如 HTTP Header、Cookie、Query Parameter 等)将流量路由到不同的版本:

  • 版本 A:满足特定条件的用户访问旧版本
  • 版本 B:满足其他条件的用户访问新版本

Istio 也支持基于请求头、uri、schema 等方式的细粒度流量管理,这种路由方式比较适用于 新版本上线时的 AB 测试。 Istio 请求头匹配介绍: https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPMatchRequest ,

在上述第5小节中,最后已经将全部的流量导向v2版本,也就是有黑色星星的版本。假如又开发了一个新版v3,此时只想要公司内部先进行测试,可以配置 VirtualService 指定部 分用户访问新版本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 还是基于名字是reviews-vs的VirtualService进行修改
[root@k8s-master01 26-istio]# kubectl get vs -n bookinfo
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["bookinfo.ibstd.com"] 5d23h
reviews-vs ["reviews"] 26h


#下面是修改前的原配置,所有流量都路由到v2版本
[root@k8s-master01 26-istio]# kubectl edit vs -n bookinfo reviews-vs
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
creationTimestamp: "2026-11-02T06:03:22Z"
generation: 3
name: reviews-vs
namespace: bookinfo
resourceVersion: "104733182"
uid: 64f1f82a-691d-43ea-a094-ba25bcd63067
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
weight: 0
- destination:
host: reviews
subset: v2
weight: 100

# 配置请求头,将携带指定请求头的请求路由到v3版本,也就是能看到红色的星星
[root@k8s-master01 26-istio]# kubectl edit vs -n bookinfo reviews-vs
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
creationTimestamp: "2026-11-02T06:03:22Z"
generation: 4
name: reviews-vs
namespace: bookinfo
resourceVersion: "105244686"
uid: 64f1f82a-691d-43ea-a094-ba25bcd63067
spec:
hosts:
- reviews
http:
- match:
- headers: # 定义请求头匹配条件集合
end-user: # 指定需检测的自定义 HTTP Header 键名(Key)是end-user
exact: test-v3 #匹配模式为“精确匹配”:只有请求头中test-user的值严格等于test-v3时才算命中
route: # 命中上述匹配条件后的流量转发目标
- destination:
host: reviews # 目标转发的服务名称
subset: v3 # 转发到该服务对应的 v3 版本子集,需要先在RD资源中划分好
- route: # 默认兜底路由规则,没有携带指定请求头的转发给reviews服务的v2版本子级
- destination:
host: reviews
subset: v2

通过浏览器访问,并观察页面变化:

没有配置请求头,无论页面如何刷新都只显示黑色的星星,也可以在kiali中观察流量走向,见下图:


配置请求头在请求,观察页面变化以及kiali的流量走向:

接下来登录 test-v3 用户(密码不限):这主要是因为 Bookinfo 官方示例的前端应用代码内部做了一层“登录用户名转请求头”的封装。

表面上在网页上执行的是“输入用户名点击登录”,但在底层网络请求中,本质上依然是基于 HTTP 请求头(Header)在进行匹配。


基于请求头的AB测试总结:

①:请求头不是 Istio 自动生成的业务身份信息,而是请求者本身携带的数据。它可以由浏览器、网关或者上游微服务设置和传递。

②:基于 Header 请求头做路由时,Key 和 Value 都必须要能匹配上VirtualService资源中定义的,例如:发起请求的一端携带了key是end-user,value是test-v3的请求头才可以根据请求头路由。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews-vs
namespace: bookinfo
spec:
hosts:
- reviews
http:
- match:
- headers: # 定义请求头匹配条件集合
end-user: #这里的end-user是请求头的key
exact: test-v3 #这里的test-v3是请求头的value
route: # 命中上述匹配条件后的流量转发目标
- destination:
host: reviews # 目标转发的服务名称
subset: v3 # 转发到该服务对应的 v3 版本子集,需要先在RD资源中划分好

上述bookinfo案例的调用链路径如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
浏览器 (Client)
│
▼
istio-ingressgateway
│
▼
productpage (Python)
│ ★ productpage 必须在代码中将 Header 转发给 reviews
▼
reviews (Java)
│ ★ reviews 必须在代码中将 Header 转发给 ratings
▼
ratings (Node.js)

bookinfo项目的productpage 并不是无条件将外部 HTTP 请求头里的 end-user 直接透传给下游,它的内部 end-user 是从用户登录会话(Session / Cookie)中提取出来的,所以通过插件工具自定义的请求头不起作用。

在微服务架构和服务网格(Service Mesh)中,只要目标服务不是链路的“第一跳”,仅靠运维在 Istio 中划分 subset 和配置 VirtualService 是无法独立完成基于 Header 的 A/B 测试的,必须依赖开发在服务调用链路中实现请求头透传(Header Propagation)。

测试 reviews服务相关功能:只需要 productpage 代码具备向下游透传该 Header 的逻辑即可;

测试 ratings服务相关功能:不仅 productpage 要透传给 reviews,**reviews 的代码也必须同样具备将该 Header 往下传递给 ratings 的逻辑**。

一句话:reviews服务做AB测试,那么调用reviews的productpage服务要能在代码中将Header转发给reviews才行,ratings服务做AB测试,那么谁调用ratings谁就要具备能携带Header发起请求才行。携带请求头发起请求需要开发人员在代码中实现该逻辑。

只要整条链路中任何一个环节的服务断开了传递,下游所有依赖该 Header 进行匹配的 VirtualService 规则就都会失效,直接退化走默认兜底版本。

7.Istio负载均衡算法

Istio 的负载均衡(Load Balancing)由底层数据面 Envoy 代理实现。在流量经过 VirtualService 路由决策后,由 DestinationRule(目标规则)决定如何将请求均匀或按特定规则分发到具体的 Pod / Endpoint 实例上。

Istio 原生支持多种负载均衡算法,比如 ROUND_ROBIN、LEAST_REQUEST、LEAST_CONN、 RANDOM 等。假如一个应用存在多个副本(Pod),可以使用上述算法对多个 Pod 进行定制化的 负载均衡配置。

常见的负载均衡算法如下:

  • ROUND_ROBIN:轮询算法,将请求按顺序依次分发给后端pod实例,不推荐使用。
  • LEAST_REQUEST:(最少请求算法),将请求分配给当前活跃请求数最少的健康实例,推荐使用。
  • RANDOM:随机算法,将请求随机分配给可用健康实例中的任意一个,不推荐使用。
  • PASSTHROUGH:(透传),不执行任何负载均衡,直接转发到调用方请求的原始目标 IP,不推荐使用。
  • UNSPECIFIED:未指定负载均衡算法,Istio 将选择一个合适的默认算法,不推荐使用。

配置示例:

负载均衡策略在 Istio 的 DestinationRule 资源中的 spec.trafficPolicy.loadBalancer 字段下进行配置。在 Istio 的 DestinationRule 中,负载均衡策略遵循继承与覆盖原则:

  • 如果在顶层的 spec.trafficPolicy.loadBalancer 定义了全局策略,所有子集(Subsets)默认继承该策略。
  • 如果在具体的 spec.subsets[].trafficPolicy.loadBalancer 中定义了策略,该子集会覆盖全局策略,仅对路由到该子集的流量生效。

①全局配置示例:

1
2
3
4
5
6
7
8
9
10
11
# 配置简单负载均衡(以 LEAST_REQUEST 为例)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: my-service-lb
namespace: default
spec:
host: my-service.default.svc.cluster.local
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST

②:subsets 中单独配置负载均衡算法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: my-service-subsets-lb
namespace: default
spec:
host: my-service.default.svc.cluster.local

# 1. 全局默认负载均衡策略(未特殊指定的 subset 会继承此策略)
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN

subsets:
# 子集 v1:覆盖全局策略,改用 LEAST_REQUEST
- name: v1
labels:
version: v1
trafficPolicy:
loadBalancer:
simple: LEAST_REQUEST

# 子集 v2:覆盖全局策略,使用基于 Cookie 的一致性哈希(会话保持)
- name: v2
labels:
version: v2
trafficPolicy:
loadBalancer:
consistentHash:
httpCookie:
name: session-token
ttl: 1800s

# 子集 v3:未显式定义 trafficPolicy,自动继承全局的 ROUND_ROBIN
- name: v3
labels:
version: v3

删除之前配置的一些路由策略,然后把dr中的负载均衡算法改为ROUND_ROBIN,访问站点并观查 Kiali 中 reviews 的流量分配:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 删除vs
[root@k8s-master01 ~]# kubectl delete vs -n bookinfo reviews-vs
virtualservice.networking.istio.io "reviews-vs" deleted

#修改dr的负载均衡算法为ROUND_ROBIN
[root@k8s-master01 ~]# kubectl edit dr -n bookinfo reviews-dr
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
creationTimestamp: "2026-11-01T09:50:11Z"
generation: 2
name: reviews-dr
namespace: bookinfo
resourceVersion: "105752567"
uid: ca082bbc-352f-46b6-9f52-5c4c0278b5d3
spec:
host: reviews
subsets:
- labels:
version: v1
name: v1
- labels:
version: v2
name: v2
- labels:
version: v3
name: v3
#在spec下添加一下参数,和host同级,针对全局的子级都生效
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN

观察流量分配基本是1:1分配的:

8.Istio熔断机制

Istio 中的熔断机制(Circuit Breaking) 是一种微服务架构中的弹性设计模式,灵感来源于现实生活中的电路保险丝。

当某个服务或实例因为过载、异常、延迟增大而开始大量报错时,熔断机制会主动切断对该故障实例/服务的流量,让调用端快速失败,防止故障扩散。

熔断的核心目标是防止故障进一步蔓延和控制增量负载,而不是暴力中止存量任务。熔断器被触发的那一刻,系统采取的是“关门打狗,消化存量,拒绝增量”的机制,也就是说触发熔断后不在接受新的请求,已经接受的请求正常处理。

在分布式微服务架构中,熔断机制主要用于解决以下问题:

  • 防止服务雪崩(Cascading Failures)
    • 场景:服务 A 调用服务 B,由于服务 B 响应极慢甚至无响应。
    • 问题:服务 A 会因为等待 B 的响应而耗尽线程、连接池或内存,导致服务 A 也崩溃,进而连环拖垮上游的服务,导致整个系统瘫痪。
    • 作用:熔断后,请求直接快速失败,不再阻塞等待,保护了上游服务。
  • 故障隔离与快速失败(Fast Failure)
    • 客户端不必经历长时间的超时等待,而是几乎立刻收到错误响应(如 HTTP 503),提升用户体验或触发降级兜底逻辑。
  • 给故障服务“自我恢复”的空间
    • 如果后端实例过载,继续涌入流量只会让其雪崩。熔断切断流量后,后端实例可以处理完手头的堆积任务,释放内存或重启,逐步恢复正常。
  • 主动剔除不健康实例(异常点检测)
    • Istio 支持基于统计数据(如连续返回 5xx 错误达到阈值),将特定的 Pod 实例移出负载均衡池一段时间,流量自动路由到健康的 Pod。

8.1Istio熔断过载保护配置

在 Istio 中,熔断保护策略是通过 DestinationRule (DR) 配置在被调用的目标服务(下游 / 服务提供方)上,但实际生效和执行熔断拦截的位置是在发起调用的客户端(上游 / 调用方)Sidecar Envoy 中。

例如架构链路为:Service A (调用方/客户端) -> Service B (被调用方/服务端)

熔断策略必须绑定到服务 Service B 的 DestinationRule。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: service-b-circuit-breaker
namespace: default
spec:
host: service-b.default.svc.cluster.local # 目标服务(被调用方)
trafficPolicy:
connectionPool:
tcp:
maxConnections: 100
http:
http1MaxPendingRequests: 10
outlierDetection:
consecutive5xxErrors: 3
interval: 10s
baseEjectionTime: 30s
maxEjectionPercent: 100

假设对 ratings 进行熔断,希望在并发请求数超过 3,并且存在 1 个以上的待处理请求,就触 发熔断,此时可以配置 ratings 的 DestinationRule 如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[root@k8s-master01 26-istio]# cat ratings-dr.yaml
apiVersion: networking.istio.io/v1 # API 版本,指定使用 Istio 网络资源的 v1 版本
kind: DestinationRule # 资源类型,指定使用 DestinationRule 资源,用于定义服务的流量策略(如负载均衡、连接池、熔断等)
metadata: # 定义该DR资源的元数据
name: ratings-dr #定义该DR资源的名称
namespace: bookinfo #定义该DR资源所属的命名空间
spec: # 定义该DR资源的具体配置
host: ratings #目标服务的主机名,即该DR资源的规则作用于哪个服务,这里填的是Service的名字
trafficPolicy: # 流量策略配置(应用于该 host 的所有子集,除非被子集覆盖)
loadBalancer: # 负载均衡策略
simple: LEAST_REQUEST # 简单负载均衡策略,选择连接数最少的服务实例
connectionPool: # 连接池配置,用于限制到目标服务的连接数和请求数
tcp: # TCP 连接池配置
maxConnections: 3 # 到目标主机的最大 TCP 连接数。超过此值的新连接会被拒绝
http: # HTTP 连接池配置
http1MaxPendingRequests: 1 #HTTP/1.1 最大等待请求数(排队请求上限)。超过此值的请求会被拒绝
outlierDetection: # 异常点检测(熔断)配置,用于自动剔除不健康的实例
consecutive5xxErrors: 1 # 连续返回 5xx 错误的次数阈值。达到此次数后将该实例标记为不健康并剔除
interval: 20s # 异常检测的扫描间隔。每隔 10 秒检查一次实例健康状态
baseEjectionTime: 30s # 熔断时长,该实例在30秒内不接受新的请求。
#实际驱逐时间 = baseEjectionTime × 当前累计驱逐次数(指数退避),防止抖动实例频繁上下线
maxEjectionPercent: 100 # 最大可剔除实例百分比。允许最多剔除 100% 的实例(即全部剔除)
# 设为 100 表示即使所有实例都异常,也全部驱逐(此时流量将全部失败)
# 生产环境建议设为 30~50,保留部分实例以维持最低可用性,避免全量摘除导致服务完全不可用
subsets:
- name: v1
labels:
version: v1

创建资源:

1
2
3
4
5
6
7
[root@k8s-master01 26-istio]#  kubectl create -f ratings-dr.yaml -n bookinfo
destinationrule.networking.istio.io/ratings-dr created

[root@k8s-master01 26-istio]# kubectl get dr -n bookinfo
NAME HOST AGE
ratings-dr ratings 15s
reviews-dr reviews 4d23h

接下来创建一个测试服务,istio官方提供的服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 创建测试服务,官方提供的测试服务路径位于istio-1.24.3/samples/httpbin/sample-client/fortio-deploy.yaml,创建pod前先修改默认的镜像下载地址,我已经将镜像同步到我的阿里云仓库,地址是registry.cn-beijing.aliyuncs.com/k8s-liujunwei/fortio:latest

[root@k8s-master01 sample-client]# vim fortio-deploy.yaml
# 将image中的地址改成同步后的镜像地址
labels:
app: fortio
spec:
containers:
- name: fortio
image: registry.cn-beijing.aliyuncs.com/k8s-liujunwei/fortio:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http-fortio
- containerPort: 8079
name: grpc-ping

创建测试服务,服务创建在bookinfo空间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@k8s-master01 sample-client]# kubectl create -f fortio-deploy.yaml -n bookinfo
service/fortio created
deployment.apps/fortio-deploy created

#查看
[root@k8s-master01 sample-client]# kubectl get po -n bookinfo
NAME READY STATUS RESTARTS AGE
details-v1-5655bbb7bb-98zbx 2/2 Running 4 (4d4h ago) 10d
fortio-deploy-768f5c8875-2r5s7 2/2 Running 0 30s
productpage-v1-7f86d94f89-6p28z 2/2 Running 4 (4d4h ago) 10d
ratings-v1-6dccb8487d-q2cgd 2/2 Running 4 (4d4h ago) 10d
reviews-v1-5c8cf97b4d-xnvhd 2/2 Running 4 (4d4h ago) 10d
reviews-v2-7685b9f4f4-4g7b2 2/2 Running 4 (4d4h ago) 10d
reviews-v3-846946d6cb-k9x7m 2/2 Running 4 (4d4h ago) 10d

等待pod启动成功进行测试,发送一个请求,可以看到当前状态码为 200,即连接成功:

1
2
3
4
5
6
7
8
9
10
11
12
[root@k8s-master01 sample-client]# kubectl exec -ti -n bookinfo fortio-deploy-768f5c8875-2r5s7  -- fortio load -curl  http://ratings:9080/ratings/0
10:33:09.201 r1 [INF] scli.go:124> Starting, command="Φορτίο", version="1.76.0 h1:CSeuqtbKDwX34cTsjcV0VDYjCCJeQ/sYTPDtIakFmrs= go1.26.9 amd64 linux", go-max-procs=4
HTTP/1.1 200 OK
content-type: application/json
date: Fri, 06 Nov 2026 10:33:09 GMT
x-envoy-upstream-service-time: 51
server: envoy
transfer-encoding: chunked

30
{"id":0,"ratings":{"Reviewer1":5,"Reviewer2":4}}
0

接下来增加并发连接(-c 1000)和总请求数量( -n 5000):

1
2
3
4
5
6
7
[root@k8s-master01 26-istio]# kubectl exec -ti -n bookinfo fortio-deploy-768f5c8875-2r5s7  -- fortio load -c 1000 -qps 0 -n 5000 -loglevel Warning http://ratings:9080/ratings/0 | grep Code
Code 200 : 5000 (100.0 %)
[root@k8s-master01 26-istio]# kubectl exec -ti -n bookinfo fortio-deploy-768f5c8875-2r5s7 -- fortio load -c 1000 -qps 0 -n 5000 -loglevel Warning http://ratings:9080/ratings/0 | grep Code
Code 200 : 1310 (26.2 %)
Code 503 : 3690 (73.8 %)
[root@k8s-master01 26-istio]# kubectl exec -ti -n bookinfo fortio-deploy-768f5c8875-2r5s7 -- fortio load -c 1000 -qps 0 -n 5000 -loglevel Warning http://ratings:9080/ratings/0 | grep Code
Code 503 : 5000 (100.0 %)

问题总结:

限流和熔断是两套完全独立、解决不同问题的保护机制。它们经常一起配置,但触发条件、作用对象和行为模式截然不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
connectionPool:  # 连接池配置,用于限制到目标服务的连接数和请求数
tcp: # TCP 连接池配置
maxConnections: 3 # 到目标主机的最大 TCP 连接数。超过此值的新连接会被拒绝
http: # HTTP 连接池配置
http1MaxPendingRequests: 1 #HTTP/1.1 最大等待请求数(排队请求上限)。超过此值的请求会被拒绝
outlierDetection: # 异常点检测(熔断)配置,用于自动剔除不健康的实例
consecutive5xxErrors: 1 # 连续返回 5xx 错误的次数阈值。达到此次数后将该实例标记为不健康并剔除
interval: 20s # 异常检测的扫描间隔。每隔 10 秒检查一次实例健康状态
baseEjectionTime: 30s # 熔断时长,该实例在30秒内不接受新的请求。
#实际驱逐时间 = baseEjectionTime × 当前累计驱逐次数(指数退避),防止抖动实例频繁上下线
maxEjectionPercent: 100 # 最大可剔除实例百分比。允许最多剔除 100% 的实例(即全部剔除)
# 设为 100 表示即使所有实例都异常,也全部驱逐(此时流量将全部失败)
# 生产环境建议设为 30~50,保留部分实例以维持最低可用性,避免全量摘除

⚠️ 常见混淆点:

❌ 误解:”超过 maxConnections 就是熔断了”

✅ 正解:超过 maxConnections 只是连接池限流,熔断必须依赖后端返回的错误

❌ 误解:”两者配一个就够了”

✅ 正解:它们互补而非替代

  • 只有限流 → 后端某个实例挂了,流量仍会持续打向它(直到超时)
  • 只有熔断 → 突发流量可能瞬间压垮所有健康实例(来不及积累5xx就被打挂)
  • 两者配合 → 限流挡住突发洪峰,熔断隔离慢性故障

💡 一句话总结:

限流是”我不发太多”,熔断是”你不行了我就换人”。前者保护下游不被过载,后者保护自己不被拖死。生产环境中建议同时配置,形成纵深防御。

9.Istio链路可靠性测试

Istio 的延迟注入(Delay Fault Injection)本质上是混沌工程(Chaos Engineering)工具,不是用来“常驻运行”的功能。延迟注入本身不解决问题,它只是把问题“提前暴露出来”。

它的核心价值是:主动、可控地模拟上游服务变慢,从而验证你的微服务系统在真实网络抖动、下游过载、GC 停顿、跨区延迟等场景下,是否真的具备容错能力。

9.1Istio注入延迟故障

Bookinfo 的核心调用关系是:

1
2
3
4
5
6
7
8
用户
↓
productpage
├──→ details (直接调用)
└──→ reviews
├── reviews-v1:不调用 ratings
├── reviews-v2:显示黑色星星,并调用 ratings服务
└── reviews-v3:显示红色星星,并调用 ratings服务

测试场景是模拟当 productpage调用 details变慢时,整个链路会发生什么?所以目标是让 productpage→ details 这一跳变慢。那么注入延迟的配置就应该在被调用的服务(details)的 VirtualService 上进行配置。

原因:

  • Istio 的故障注入(fault injection)是由客户端代理执行的(调用方的 sidecar 或 waypoint)。
  • 你在 目标服务(ratings) 的 VirtualService 里写 fault.delay,Istio 会把这个规则下发给所有调用 details 的客户端代理。
  • 当 productpage 的代理准备把请求发给 details 时,它会先按照规则延迟,再真正转发。

首先观察服务正常时的状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 创建一个测试pod来测试延迟
[root@k8s-master01 26-istio]# kubectl create deploy -n bookinfo debug-tools --image=registry.cn-beijing.aliyuncs.com/dotbalo/debug-tools -- sleep 36000
deployment.apps/debug-tools created

[root@k8s-master01 26-istio]# kubectl get po -n bookinfo
NAME READY STATUS RESTARTS AGE
debug-tools-79bc9d974b-dgq75 0/2 PodInitializing 0 22s
details-v1-5655bbb7bb-98zbx 2/2 Running 6 (19h ago) 11d
fortio-deploy-768f5c8875-2r5s7 2/2 Running 3 (19h ago) 21h
productpage-v1-7f86d94f89-6p28z 2/2 Running 6 (19h ago) 11d
ratings-v1-6dccb8487d-5hchn 2/2 Running 2 (19h ago) 19h
reviews-v1-5c8cf97b4d-xnvhd 2/2 Running 6 (19h ago) 11d
reviews-v2-7685b9f4f4-4g7b2 2/2 Running 6 (19h ago) 11d
reviews-v3-846946d6cb-k9x7m 2/2 Running 6 (19h ago) 11d

#进入pod测试请求details服务的延迟
[root@k8s-master01 26-istio]# kubectl exec -ti -n bookinfo debug-tools-79bc9d974b-dgq75 -- bash
(07:47 debug-tools-79bc9d974b-dgq75:/) time curl -I -s details:9080
HTTP/1.1 404 Not Found
content-type: text/html; charset=ISO-8859-1
server: envoy
date: Sat, 07 Nov 2026 08:01:33 GMT
content-length: 268
x-envoy-upstream-service-time: 6


real 0m0.017s #很快响应
user 0m0.004s
sys 0m0.004s

在通过web访问,可以看到没有注入延迟的情况下details也是正常显示的:

接下来通过创建ratings 服务的VirtualService 资源在注入延迟:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@k8s-master01 26-istio]# cat  details-vs.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: details-vs
namespace: bookinfo
spec:
hosts: # 【作用范围】定义这条规则对哪些目标地址生效。
- "details" # 当 Envoy 代理拦截到发往 "details" 的请求时,就会触发下面的规则。
# 可以是 K8s Service 短名称 (如 "details") ,如果vs和ratings不在同命名空间要写全成称:details.bookinfo.svc.cluster.local
# 也可以是外部域名 (如 "api.example.com")
http: #定义路由规则列表,按顺序匹配,首个命中即停止
- fault: #故障注入配置(用于混沌测试/韧性验证)
delay: # 【故障类型】延迟注入(模拟网络慢/服务响应慢)
percentage: #定义百分比
value: 100 # 【影响比例】填 0 到 100 之间的数值。100 代表对所有满足条件的流量都注入延迟。
# 生产环境调试时建议从 1-5 开始逐步增加
fixedDelay: 10s #【延迟时长】固定延迟时间,支持 s/ms/us 单位
route: #实际流量转发目标列表,上述匹配到的路由转发给谁来处理
- destination: #目的地
host: details #details是svc的名字,表示转发给details服务来处理流量
port:
number: 9080 # details服务(Service)的端口

在 Istio 的 VirtualService 中,gateways 字段是可选配置。它是否需要填写,完全取决于你要处理的是内部流量还是外部流量。

如果不填:默认只对集群内部生效 (默认值是 mesh):

如果你在编写 VirtualService 时省略了 gateways 字段,Istio 会隐式地将它设置为系统保留关键字 mesh。

  • 作用:这条路由规则只会在 Istio 网格内部生效,专门控制各个微服务之间的互相调用(东西向流量)。
  • 应用场景:比如你之前测试的 reviews 调用 ratings 服务,或者针对 ratings 配置延迟注入和熔断。这些都是内部服务间的调用,不需要配置 gateways。

什么时候必须填:对外暴露服务时:

当你希望外部用户(如浏览器、手机 App)通过域名访问你的微服务时(南北向流量),就必须填写 gateways 字段,并指定对应的 Gateway 资源名称(如你提到的 bookinfo-gateway)。

  • 作用:将这条路由规则绑定到边缘代理(istio-ingressgateway)上,让外网进来的流量知道该怎么转发。
  • 应用场景:比如你之前配置 bookinfo.ibstd.com 域名来访问前端 productpage 服务,如果不在此处的 VS 中绑定 bookinfo-gateway,外部流量到了网关就会因为找不到路由规则而返回 404。

创建上述VirtualService资源:

1
2
[root@k8s-master01 26-istio]#  kubectl create -f details-vs.yaml -n bookinfo
virtualservice.networking.istio.io/details-vs created

再次通过web端和测试pod测试,查看现象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#可以可能到响应时间大于10秒
[root@k8s-master01 26-istio]# kubectl exec -ti -n bookinfo debug-tools-79bc9d974b-dgq75 -- bash
(130 08:05 debug-tools-79bc9d974b-dgq75:/) time curl -I -s details:9080 #测试命令
HTTP/1.1 404 Not Found
content-type: text/html; charset=ISO-8859-1
server: envoy
date: Sat, 07 Nov 2026 08:06:20 GMT
content-length: 268
x-envoy-upstream-service-time: 53


real 0m10.065s #10秒后才响应
user 0m0.004s
sys 0m0.004s
(08:06 debug-tools-79bc9d974b-dgq75:/)


上图篮筐中的就是针对「超时 + 友好降级」的成功提示。这在生产环境中是健康的表现,而不是故障。这是针对响应慢的问题给出了友好的提示信息,是完全预期的行为,也是延迟注入要验证的核心点。

延迟注入的目的就是提前暴露和验证这种行为。

如果注入 10s 延迟后,整个页面都卡住或直接 500,说明你的超时和错误处理没有做好,需要去改代码的处理逻辑。

9.2Istio注入中断故障

Istio 的中断故障注入(Abort Fault Injection)是指:通过 Envoy 代理人为地、立刻掐断请求,并直接向上游服务返回一个指定的 HTTP 错误状态码(如 503、500 或 404)。

如果说之前的延迟注入(Delay)模拟的是“服务变卡、网络拥堵”,那么中断注入(Abort)模拟的就是“服务直接挂掉、拒绝连接或内部崩溃”(Fail-Fast),用来检验系统在下游服务直接出错时的表现。

它和之前的延迟注入(Delay)是两种不同的故障类型:

类型 作用 模拟的真实场景 常见配置
Delay(延迟) 让请求卡住一段时间再转发 网络延迟、下游服务过载、慢查询 fixedDelay: 5s
Abort(中断) 直接返回错误,不转发到真实服务 服务宕机、进程崩溃、返回 5xx、连接被拒绝 httpStatus: 500 或 503

还是在bookinfo项目上测试,场景是模拟当 productpage调用 details时,details服务直接故障,整个链路会发生什么?所以目标是让 productpage→ details 这一跳故障。那么注入故障的配置就应该在被调用的服务(details)的 VirtualService 上进行配置。

创建故障注入的vs资源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 中断故障注入只需要将 fault 的 delay 更改为 abort 即可
[root@k8s-master01 26-istio]# vim details-abort-vs.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: details-abort-vs
namespace: bookinfo
spec:
# 1. 作用的主机名(域名或 K8s 内部短/长域名)
hosts:
- "details"
http:
- fault: # 注入故障参数,固定值
abort: #【故障类型二选一】abort 或 delay,也可同时配置
percentage: # 定义影响范围的百分比
value: 100 # 【影响比例】填 0 到 100 之间的数值。100 代表对所有满足条件的流量都注入abort故障。
httpStatus: 500 # 【伪造的状态码】(必填) 强制向上游调用方返回的具体 HTTP 错误码。常用如 500 (模拟内部代码崩溃)、503 (模拟过载或不可用)、403 (模拟权限拒绝) 等。
route:
- destination:
host: details
port:
number: 9080

创建资源:

1
2
[root@k8s-master01 26-istio]# kubectl create -f details-abort-vs.yaml  -n bookinfo
virtualservice.networking.istio.io/details-abort-vs created

web端展示的和延迟故障展示的一样,这里就不演示了,表示同样遇到服务故障也会友好的展示提示信息,而不是等着整个页面的加载。