服务网格Istio安装及使用

在k8s中配置启用了istio之后,在创建pod之后会自动注入一个Envoy这样的容器,可理解为代理容器,也就是说,创建pod是除了定义的一个主容器,还会在启动istio之后自动注入一个容器,一个pod有两个容器,该代理容器主要是用来做流量的控制和管理,能做到流量的拦截,能控制熔断、超时、重试,按流量的百分比代理等作用。

流量管理

熔断

当在 K8s集群中使用 Istio 时,可以通过 Istio 提供的熔断功能来增加微服务架构的稳定性和可靠性。

熔断是一种故障保护机制,用于在服务之间的通信中防止故障扩散,并提供更好的容错能力。

在微服务架构中,一个应用通常由许多小型的、相互协作的服务组成。当某个服务发生故障或变得不可用时,如果不采取措施,可能会导致连锁反应,影响到整个系统的可用性。

熔断机制旨在解决这个问题,其核心思想是在服务之间设置阈值和超时时间,并对请求进行监控。当服务的错误率或响应时间超过预设的阈值时,熔断器会打开,拒绝向该服务发送更多请求,并快速失败返回错误,而不是等待超时。

应用场景如下:

1
2
3
4
5
6
7
8
9
10
11
1.快速失败返回:
当目标服务不可用时,不再尝试等待请求超时,而是快速返回错误,从而避免资源浪费和潜在的长时间等待。

2.故障隔离:
熔断机制阻止故障扩散,使问题局限在出现故障的服务,而不会影响到整个应用程序。

3.恢复机制:
熔断器会定期尝试发起一些请求到目标服务,以检查其是否已经恢复。如果服务恢复正常,则熔断器会逐渐关闭,允许流量再次流向目标服务。

4.自动重试:
一旦目标服务恢复,熔断器会逐渐允许一部分流量通过,如果没有再次出现问题,会逐渐恢复到正常状态,否则继续保持熔断状态。

超时

在 K8s集群中结合 Istio,可以使用 Istio 的流量管理功能来控制服务之间的请求超时。

超时是指在一定时间内,如果某个请求没有得到及时响应,就会被认为是超时。

通过设置请求超时时间,可以对服务之间的通信进行控制,确保请求在合理的时间内得到响应,避免请求无限期地等待导致资源浪费或影响整体系统的响应性能。

Istio 的超时控制允许你为每个服务之间的请求设置最大的等待时间。

当某个请求在指定的超时时间内没有得到响应时,Istio 会终止该请求并返回一个错误响应给客户端。

这样可以防止请求在后端服务长时间等待,从而避免请求积压,同时提高系统的稳定性和可用性。

超时控制的意义如下:

1
2
3
4
5
6
7
8
9
10
1.防止长时间等待:
通过设置合理的请求超时时间,避免了客户端请求在后端服务长时间等待导致的响应延迟,从而提高了用户体验。

2.快速失败机制:
当后端服务无法及时响应请求时,超时控制会快速返回错误响应,而不是让请求无限期地等待,从而避免资源浪费。

3.故障隔离:
如果某个服务出现故障或变得不可用,超时控制可以快速终止对该服务的请求,避免故障扩散到其他服务。

在 Istio 中,超时控制是通过配置请求超时策略来实现的。你可以为每个服务定义超时时间,也可以为整个服务部署或命名空间设置默认的超时时间。这样,Istio 会根据配置中的超时时间来对请求进行限制,保证请求在规定时间内得到响应。

Istio组件

pilot

Pilot 是 Istio 控制平面的组件,在istio系统中,Pilot 完成以下任务:

它从服务注册中心(如Kubernetes的etcd或Consul)获取服务和实例的信息,并为Envoy生成配置,Envoy 根据 Pilot 发过来的配置里的内容,完成具体流量的转发。

Pilot可以被认为是团队的领袖。它负责监督和指导队伍中的每个Envoy。

Pilot指导整个团队中每个服务的位置,以及它们应该如何相互协作。

当有新队员加入或者队员的位置变化时,Pilot会负责通知每个队员,确保大家都知道最新的情况,不会出现迷路或者错过重要信息,会把要做的事形成文件下发到每个envoy队员里。

envoy

Envoy是Istio中的代理,我们如果开启了istio功能,会在pod里自动注入Envoy代理容器,它负责处理服务之间的所有网络通信,拦截并转发所有的HTTP、TCP和gRPC流量。

Envoy提供强大的流量控制和管理功能,如路由、重试、超时和故障注入等。

Envoy和主容器同属于一个Pod,共享网络和命名空间,Envoy代理进出Pod 的流量,并将流量按照外部请求的规则作用于主容器中。

Envoy可以看作是服务之间的守护者。它像一个中间人一样,坐在每个服务旁边(就像每个队员身边都有一个保镖一样)。它负责处理服务之间的所有信息传递,确保信息传送得又快又准确。如果有请求从一个服务发出,Envoy会帮它找到正确的目标服务并将请求送达过去。它还能处理各种不同类型的请求,就像精通各种语言的翻译一样。

galley

Galley是Istio的配置管理组件,负责验证、转换和分发配置给其他Istio组件。

它监听Kubernetes的配置更改,例如Service、Deployment等,然后根据规则和策略生成Istio所需的配置,并将其提供给Pilot和其他组件。

Galley可以被看作是团队中的文件管理员。它负责管理团队中所有的文件和信息,确保每个队员都能得到正确的信息和文件。当有新的文件产生或者文件发生变化时,Galley会及时通知团队中的每个成员,确保大家都使用的是最新的文件,不会出现信息不同步的问题。

Ingressgateway

istio-ingressgateway是Istio服务网格中的一个特殊网关,它作为整个网格的入口,接收外部请求,并将它们引导到内部的服务。

可以将它比作一个大门保安,负责接收外部人员的访问请求,然后根据配置的规则将请求分发给网格内部的服务。

简单来说,当有外部的请求访问Istio服务网格时,它们会先被送到istio-ingressgateway。

这个网关会检查请求,并根据一些规则判断该请求应该交给哪个服务来处理。

然后,它将请求转发给网格内部的相应服务,从而实现外部请求与内部服务的连接。

egressgateway

istio-egressgateway是Istio服务网格中的另一个特殊网关,它负责处理网格内部服务对外部服务的访问请求。

可以将它看作是一个网格内部的出口,负责将内部服务需要访问的外部服务请求发送到外部。

以将istio-egressgateway比作一个秘书,它会代表网格内部的服务,帮助它们联系外部的服务。

当网格内部的服务需要访问外部服务时,它们会将请求交给istio-egressgateway,然后由这个网关将请求发送给外部服务。

安装/卸载istio

当安装完成istio之后,就会自动生成三个pod,分别为:istiod、Ingressgateway、egressgateway,然后就可以使用它的熔断、超时、重试等功能。

1
2
3
注意:
由于k8s集群在1.24版本之后使用的容器运行时不同,那么所安装istio的方法也不同,下面是k8s集群版本1.24前后的安装istio方式
在大于等于k8s集群1.24版本的情况下需要安装的istio版本要大于等于1.18版本。

k8s集群小于等于1.23版本安装istio

k8s集群版本:1.23.1

下载istio的安装包:

官网下载地址:https:///istio/istio/

GitHub下载地址: https:///istio/istio/tags

这里使用的版本是istio:1.13.1 (可使用wget 下载)

1
wget  https:///istio/istio/releases/download/1.13.1/istio-1.13.1-linux-amd64.tar.gz
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#下载到k8s集群的master节点并解压
[root@k8s-master ~]# tar zxf istio-1.13.1.tar.gz
[root@k8s-master ~]# cd istio-1.13.1
[root@k8s-master istio-1.13.1]# cp bin/istioctl /usr/bin/ //拷贝执行文件到/usr/bin下
[root@k8s-master istio-1.13.1]# istioctl install --set profile=demo -y //初始化安装,如下所示表示安装成功。
✔ Istio core installed
✔ Istiod installed
✔ Egress gateways installed
✔ Ingress gateways installed
✔ Installation complete
Making this installation the default for injection and validation.

Thank you for installing Istio 1.13. Please take a few minutes to tell us about your install/upgrade experience! https://forms.gle/pzWZpAvMVBecaQ9h9


#安装成功之后,查看istio的pod是否运行成功,如下
[root@k8s-master istio-1.13.1]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-egressgateway-76c96658fd-78ll2 1/1 Running 0 114s
istio-ingressgateway-569d7bfb4-pg5vz 1/1 Running 0 114s
istiod-74c64d89cb-xdxn4 1/1 Running 0 2m41s

k8s集群大于等于1.24版本安装istio

k8s集群版本:1.28.1

下载istio的安装包:

官网下载地址: https:///istio/istio/

GitHub下载地址: https:///istio/istio/tags

这里使用的版本是istio:1.182 (可使用wget 下载)

1
wget  https:///istio/istio/releases/download/1.18.2/istio-1.18.2-linux-amd64.tar.gz
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
[root@k8s-master ~]# tar -zxvf istio-1.18.2-linux-amd64.tar.gz
[root@k8s-master ~]# cd istio-1.18.2
[root@k8s-master istio-1.18.2]# cp bin/istioctl /bin/
[root@k8s-master istio-1.18.2]# istioctl install --set profile=demo -y //如下表示安装成功
✔ Istio core installed
✔ Istiod installed
✔ Ingress gateways installed
✔ Egress gateways installed
✔ Installation complete
Making this installation the default for injection and validation.


#验证pod运行情况
[root@k8s-master istio-1.18.2]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-egressgateway-5499894f8d-nvtrv 1/1 Running 0 22s
istio-ingressgateway-77fbf9d476-thtnp 1/1 Running 0 22s
istiod-77c989fb-4xf8g 1/1 Running 0 27s


#不同于k8s集群1.23以下版本的安装方法就是使用的容器运行时不同,
#如使用containerd初始化安装istio时下载镜像失败,那么就是containerd没有配置好或者镜像源不可用等问题
#可以使用docker下载相关依赖镜像在打包传到containerd
#使用docker下载如下两个镜像并打包传到k8s工作节点上的containerd中,再进行初始化安装istio步骤即可。
#/istio/pilot:1.18.2
#/istio/proxyv2:1.18.2

安装命令选项

1
2
3
4
5
6
istioctl install --set profile=demo -y

profile=""
1.demo:适用于生产环境,会创建三个pod,包含istiod、ingressgateway、egressgateway
2.default:这是一个最小配置,仅包含最基本的组件,如istiod和ingressgateway
3.minimal:这个配置相对更加精简,只包含了必需的组件,适用于资源受限或轻量级的环境。只会安装istiod。

通过如下命令可以看到选择安装的模式下都有哪些配置文件

如查看demo模式:

1
istioctl profile dump demo

卸载istio

1
2
3
4
5
6
7
#该卸载方式会保留名称空间等一些组件遗留
[root@k8s-master istio-1.18.2]# istioctl manifest generate --set profile=demo | kubectl delete -f -

#执行完上述卸载命令之后也可以再次执行如下命令完全卸载。
[root@k8s-master istio-1.18.2]# istioctl x uninstall --purge //提示中输入y即可完全卸载

#如需重新安装继续执行istioctl install --set profile=demo -y即可。

k8s集群部署在线书店,启用istio

使用istio自带的工具进行部署,如下步骤中的yaml文件都在解压istio压缩包中自带的。

在线书店(Bookinfo)应用分为四个单独的微服务

1
2
3
4
1)productpage这个微服务会调用details和reviews两个微服务,用来生成前端页面;
2)details这个微服务中包含了书籍的信息;
3)reviews这个微服务中包含了书籍相关的评论,它还会调用ratings微服务;
4)ratings这个微服务中包含了由书籍评价组成的评级信息。

reviews微服务有3个版本

1)v1版本不会调用ratings服务;

2)v2版本会调用ratings服务,并使用1到5个黑色星形图标来显示评分信息;

3)v3版本会调用ratings服务,并使用1到5个红色星形图标来显示评分信息。

配置istio自动注入代理容器功能

部署应用前还需要为默认名称空间打上一个标签,可理解为开启istio自动注入代理容器功能。

因为下面步骤创建的pod等资源都在默认名称空间下创建,所以为默认名称空间打赏标签,

istio默认自动注入 sidecar,需要为default命名空间打上标签 istio-injection=enabled,这样在默认空间下创建pod istio就可以自动注入一个代理容器。

注:在别的名称空间创建pod时,要想istio自动注入代理容器,也要打上相同的标签

1
2
3
4
5
6
7
8
#打标签
[root@k8s-master ~]# kubectl label namespace default istio-injection=enabled
namespace/default labeled

#验证查看
[root@k8s-master ~]# kubectl get ns --show-labels | egrep -i "status|default"
NAME STATUS AGE LABELS
default Active 18d istio-injection=enabled,kubernetes.io/metadata.name=default

关闭 istio自动注入代理容器功能

如上所示,要想关闭istio自动注入代理容器功能,则需要将istio-injection=enabled该标签从名称空间上取消。

为了不影响下方的实验,该步骤功能了解即可,不用操作。

1
2
3
4
5
6
7
8
#删除标签
[root@k8s-master ~]# kubectl label ns default istio-injection-
namespace/default unlabeled

#验证查看
[root@k8s-master ~]# kubectl get ns --show-labels | egrep -i "status|default"
NAME STATUS AGE LABELS
default Active 18d kubernetes.io/metadata.name=default

部署应用

如下步骤使用的集群版本为1.28.1,容器运行时使用的是containerd

准备如下镜像到k8s集群的工作节点中

(不准备也可以,直接使用istio自带的yaml文件时也会自动下载)

1
2
3
4
5
6
/istio/examples-bookinfo-details-v1:1.17.0
/istio/examples-bookinfo-productpage-v1:1.17.0
/istio/examples-bookinfo-ratings-v1:1.17.0
/istio/examples-bookinfo-reviews-v1:1.17.0
/istio/examples-bookinfo-reviews-v2:1.17.0
/istio/examples-bookinfo-reviews-v3:1.17.0
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#进入到istio压缩包解压后的路径中,使用istio自带的yaml文件创建资源
[root@k8s-master ~]# cd istio-1.18.2/samples/bookinfo/platform/kube/ //进入到目标路径
[root@k8s-master kube]# kubectl apply -f bookinfo.yaml //找到目标yaml文件并执行创建
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,yaml文件中默认定义的是一个容器服务,这里的2/2说明自动注入的代理容器也成功了。
[root@k8s-master kube]# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
details-v1-65fbc6fbcf-f69qp 2/2 Running 0 5m22s 10.244.194.75 k8s-worker1 <none> <none>
productpage-v1-78d88f8f58-v57dx 2/2 Running 0 5m22s 10.244.194.77 k8s-worker1 <none> <none>
ratings-v1-7fcc55c79f-vqmhc 2/2 Running 0 5m22s 10.244.194.76 k8s-worker1 <none> <none>
reviews-v1-66c7d54957-nw96c 2/2 Running 0 5m22s 10.244.194.72 k8s-worker1 <none> <none>
reviews-v2-844777b87c-nch5l 2/2 Running 0 5m22s 10.244.194.73 k8s-worker1 <none> <none>
reviews-v3-b48665d5c-7m96m 2/2 Running 0 5m22s 10.244.194.74 k8s-worker1 <none> <none>

#验证查看创建svc
[root@k8s-master kube]# kubectl get svc -owide | grep -v kubernetes
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
details ClusterIP 10.101.228.3 <none> 9080/TCP 5m55s app=details
productpage ClusterIP 10.102.85.97 <none> 9080/TCP 5m55s app=productpage
ratings ClusterIP 10.99.175.240 <none> 9080/TCP 5m55s app=ratings
reviews ClusterIP 10.99.185.174 <none> 9080/TCP 5m55s app=reviews


#使用七层代理访问bookinfo的前端pod(productpage-v1-78d88f8f58-v57dx),需要创建网关及虚拟服务
[root@k8s-master kube]# cd
[root@k8s-master ~]# cd istio-1.18.2/samples/bookinfo/networking/ //进入目标路径
[root@k8s-master networking]# cat bookinfo-gateway.yaml

apiVersion: /v1alpha3
kind: Gateway #在默认名称空间创建网关资源,安装完成istio之后才会有的一个资源
metadata:
name: bookinfo-gateway
spec:
selector: #标签选择器指定了具有istio: ingressgateway这个标签的pod,详见下图一,
istio: ingressgateway
servers: #如下指定了监听端口80及http的协议
- port:
number: 80
name: http
protocol: HTTP
hosts: #“*”表示访问任何域名,只要是来自http协议及端口80的请求都交给具有上面标签的pod,也就是下图一那个pod
- "*"
---
apiVersion: /v1alpha3
kind: VirtualService #创建虚拟服务,将上面创建的网关绑定到虚拟服务上。
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways: #指定上面网关的名称进行绑定
- bookinfo-gateway
http:
- match: #定义路由规则,如果请求的是如下定义的接口,(如:/productpage),那么将会该请求代理给下面定义的productpage
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route: #如上描述,将会代理给这里定义的productpage这个svc,而productpage这个svc的端口是9080,如下图二所示
- destination:
host: productpage
port:
number: 9080


#创建该yaml文件
[root@k8s-master networking]# kubectl apply -f bookinfo-gateway.yaml
gateway./bookinfo-gateway created
virtualservice./bookinfo created

#查看验证
[root@k8s-master networking]# kubectl get gateway
NAME AGE
bookinfo-gateway 51s
[root@k8s-master networking]# kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["*"] 63s

访问验证

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
#访问上面bookinfo-gateway.yaml文件中gateway资源中指定的具有istio=ingressgateway标签的pod的前端service
#查看具有该标签的pod
[root@k8s-master networking]# kubectl get pods -l istio=ingressgateway -A -owide
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
istio-system istio-ingressgateway-77fbf9d476-tr2gd 1/1 Running 0 23h 10.244.194.71 k8s-worker1 <none> <none>

#查看该pod的前端service,通过名称确认是istio-ingressgateway
[root@k8s-master networking]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egressgateway ClusterIP 10.110.37.178 <none> 80/TCP,443/TCP 23h
istio-ingressgateway LoadBalancer 10.96.68.15 <pending> 15021:32520/TCP,80:31718/TCP,443:32483/TCP,31400:31230/TCP,15443:32205/TCP 23h
istiod ClusterIP 10.102.48.108 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 23h

#查看该svc的endpoints,通过ip再次确认
[root@k8s-master networking]# kubectl describe svc istio-ingressgateway -n istio-system | grep -i endpoints
Endpoints: 10.244.194.71:15021
Endpoints: 10.244.194.71:8080
Endpoints: 10.244.194.71:8443
Endpoints: 10.244.194.71:31400
Endpoints: 10.244.194.71:15443

#访问流量走向过程:
#浏览器访问k8s控制/工作节点的ip加具有istio=ingressgateway这个标签pod的前端service对应80端口的端口,也就是31718
#控制节点IP:192.168.57.131:31718
#访问该地址,就会把请求通过这个31718端口代理给该service的后端pod,也就是具有istio=ingressgateway这个标签pod
#然后访问指定路由/productpage,(192.168.57.131:31718/productpage),
#这样就能根据上面bookinfo-gateway.yaml文件定义的路由规则访问到productpage这个service的9080端口

#如下:
[root@k8s-master networking]# kubectl get svc | egrep -i "name|productpage"
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
productpage ClusterIP 10.102.85.97 <none> 9080/TCP 79m

#通过endpoints查看该service的后端pod
[root@k8s-master networking]# kubectl describe svc productpage | grep -i endpoints
Endpoints: 10.244.194.77:9080

#查看具有该ip的pod是哪个
[root@k8s-master networking]# kubectl get pods -owide | egrep -i "name|10.244.194.77"
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
productpage-v1-78d88f8f58-v57dx 2/2 Running 0 83m 10.244.194.77 k8s-worker1 <none> <none>


#浏览器访问如下图所示: 192.168.57.131:31718/productpage

通过Istio实现灰度发布

灰度发布也叫金丝雀部署 ,是指通过控制流量的比例,实现新老版本的逐步更替。

比如对于服务A 有两个版本 , 当前两个版本同时部署, 控制流量的访问版本1比例90% ,访问版本2比例10% ,然后根据运行的效果逐步调整流量访问占比,直至最终版本1下线。

工作节点准备两个镜像进行测试实验:

这里使用的是nginx镜像,该镜像服务状态均一致,只是版本不同,用于测试灰度发布

nginx-v1 返回版本1

nginx-v2 返回本本2

创建pod

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#使用nginx-v1镜像创建版本为1的pod
[root@k8s-master ~]# vim istio-pod-v1.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v1
labels:
app: v1
spec:
replicas: 1
selector:
matchLabels:
app: nginx-v1
test: abc
template:
metadata:
labels:
app: nginx-v1
test: abc
spec:
containers:
- name: nginx
image: nginx:v1
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80

#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-v1.yaml
deployment.apps/v1 created

[root@k8s-master ~]# kubectl get pods -owide #READY显示2/2,表示istio的代理容器也运行成功
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
v1-6b67b54dfc-qvjvl 2/2 Running 0 13s 10.244.194.95 k8s-worker1 <none> <none>

#测试返回值版本为 v1
[root@k8s-master ~]# curl 10.244.194.95
nginx-v1



#使用nginx-v2镜像创建版本为2的pod
[root@k8s-master ~]# cp istio-pod-v1.yaml istio-pod-v2.yaml
[root@k8s-master ~]# vim istio-pod-v2.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: v2
labels:
app: v2
spec:
replicas: 1
selector:
matchLabels:
app: nginx-v2
test: abc
template:
metadata:
labels:
app: nginx-v2
test: abc
spec:
containers:
- name: nginx
image: nginx:v2
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80


#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-v2.yaml
deployment.apps/v2 created

[root@k8s-master ~]# kubectl get pods -owide #READY显示2/2,表示istio的代理容器也运行成功
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
v1-6b67b54dfc-qvjvl 2/2 Running 0 2m29s 10.244.194.95 k8s-worker1 <none> <none>
v2-68c9d69c4f-jktr5 2/2 Running 0 25s 10.244.194.96 k8s-worker1 <none> <none>

#测试返回值版本为 v2
[root@k8s-master ~]# curl 10.244.194.96
nginx-v2

创建service

创建service代理两个pod:

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
#创建四层代理servic
#根据定义的标签确认后端的pod目标,找到具有test=abc的pod
[root@k8s-master ~]# kubectl get pods -l test=abc
NAME READY STATUS RESTARTS AGE
v1-6b67b54dfc-qvjvl 2/2 Running 0 4m56s
v2-68c9d69c4f-jktr5 2/2 Running 0 2m52s

#创建service
[root@k8s-master ~]# cat istio-pod-service.yaml
apiVersion: v1
kind: Service
metadata:
name: istio-pod-nginx
labels:
test: abc
spec:
selector:
test: abc
ports:
- protocol: TCP
port: 80
targetPort: 80

#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-service.yaml
service/istio-pod-nginx created

[root@k8s-master ~]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-pod-nginx ClusterIP 10.96.179.74 <none> 80/TCP 3s

[root@k8s-master ~]# kubectl describe svc istio-pod-nginx
Name: istio-pod-nginx
Namespace: default
Labels: test=abc
Annotations: <none>
Selector: test=abc
Type: ClusterIP
IP Family Policy: SingleStack
IP Families: IPv4
IP: 10.96.179.74
IPs: 10.96.179.74
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.244.194.95:80,10.244.194.96:80 //这里看到绑定的ip地址就是刚刚创建的nginx的pod的IP地址
Session Affinity: None
Events: <none>

#测试请求service,如下所示请求是轮询
[root@k8s-master ~]# curl 10.96.179.74
nginx-v2
[root@k8s-master ~]# curl 10.96.179.74
nginx-v1
[root@k8s-master ~]# curl 10.96.179.74
nginx-v2
[root@k8s-master ~]# curl 10.96.179.74
nginx-v1

创建Gateway

使用Gateway,通过istio的ingressgetway这个service,根据它映射的物理机端口31718,通过访问k8s集群节点的IP+31718,将请求交给到刚刚创建的pod前端的四层代理service,然后最终再通过这个四层代理service访问到它代理的后端pod。

istio的ingressgetway这个service的物理机映射端口如下图所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@k8s-master ~]# vim istio-pod-gzteway.yaml
apiVersion: /v1beta1
kind: Gateway
metadata:
name: istio-pod-gateway
spec:
selector:
istio: ingressgateway #查找具有该标签的pod
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts: #表示只要满足http协议的80端口的流量,那么任何域名都可以访问。
- "*"

#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-gateway.yaml
gateway./istio-pod-gateway created

[root@k8s-master ~]# kubectl get gateway
NAME AGE
bookinfo-gateway 130m
istio-pod-gateway 7s

创建虚拟服务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
[root@k8s-master ~]# vim istio-pod-vlbetal.yaml
apiVersion: /v1beta1
kind: VirtualService
metadata:
name: istio-pod-vlbetal
spec:
hosts:
- "*"
gateways: #绑定网关,指定gateway的名称
- istio-pod-gateway
http:
- route: #路由
- destination: #目标地址
host: istio-pod-nginx.default.svc.cluster.local #这里写目标地址1的名称,写的是四层代理service的名称+所在名称空间+完整域名的后缀
subset: v1 #定义子级权重。(子级也需要定义,定义自己指定的是哪个pod)
weight: 90 #定义v1的权重为90接收90%的流量
- destination:
host: istio-pod-nginx.default.svc.cluster.local #这里写目标地址2的名称,同上前面是service名称及所在名称空间,后面的后缀为默认的。
subset: v2
weight: 10 #同理,v2的权重为10,接收10%的流量


#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-vlbetal.yaml
virtualservice./istio-pod-vlbetal created

[root@k8s-master ~]# kubectl get virtualService
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["*"] 163m
istio-pod-vlbetal ["istio-pod-gateway"] ["*"] 10s

创建目标规则

创建上方virtualService的yaml文件中定义的子级指向规则:

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
[root@k8s-master ~]# vim istio-pod-vlbetal-destination.yaml
apiVersion: /v1beta1
kind: DestinationRule
metadata:
name: istio-pod-vlbetal-destination
spec:
host: istio-pod-nginx.default.svc.cluster.local #这里同样定义service的完整域名
subsets: #定义子级
- name: v1 #通过pod标签进行绑定指定
labels: #子级名称为v1的绑定具有如下标签的pod
app: nginx-v1
- name: v2 #子级名称为v2的绑定具有如下标签的pod
labels:
app: nginx-v2

#确认具有如上定义标签的pod
[root@k8s-master ~]# kubectl get pods -l app=nginx-v1
NAME READY STATUS RESTARTS AGE
v1-6b67b54dfc-qvjvl 2/2 Running 0 73m

[root@k8s-master ~]# kubectl get pods -l app=nginx-v2
NAME READY STATUS RESTARTS AGE
v2-68c9d69c4f-jktr5 2/2 Running 0 71m


#创建
[root@k8s-master ~]# kubectl apply -f istio-pod-vlbetal-destination.yaml
destinationrule./istio-pod-vlbetal-destination created

[root@k8s-master ~]# kubectl get destinationRule
NAME HOST AGE
istio-pod-vlbetal-destination istio-pod-nginx.default.svc.cluster.local 15s

#验证,定义了v1权重90,v2权重10,也就是说,访问100次只有10次可以访问到v2
#如下访问k8s集群任意的节点IP+istio的ingressgateway的service映射的物理机端口31718
#curl 192.168.57.131:31718

#使用for循环请求一百次查看结果如下
[root@k8s-master ~]# for i in {1..100};do curl 192.168.57.131:31718;done > 1.txt

#查看请求结果如下:(与设置的权重百分比虽有偏差,但是非常接近)
[root@k8s-master ~]# cat 1.txt | grep v1 | wc -l
89
[root@k8s-master ~]# cat 1.txt | grep v2 | wc -l
11

逐步增加 v2 版本的流量比例

如果 v2 版本运行稳定,我们可以逐步增加其流量比例。修改 istio-pod-vlbetal.yaml 文件中的 weight 值,例如将 v1 的权重设置为 50,v2 的权重设置为 50,然后使用 kubectl apply -fistio-pod-vlbetal.yaml命令更新配置。

高级灰度策略

除了简单的流量比例切分,Istio 还支持更高级的灰度策略,例如:

  • 基于用户 ID 的灰度: 将特定用户 ID 的流量路由到新版本。
  • 基于 HTTP Header 的灰度: 根据 HTTP Header 中的特定字段,将流量路由到新版本。
  • 基于 Cookie 的灰度: 根据 Cookie 中的特定字段,将流量路由到新版本。

这些高级策略可以帮助我们实现更精细的灰度发布,例如只让内部员工或特定用户体验新版本。

以下是一个基于 HTTP Header 的灰度示例:

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
# productpage-virtualservice-header.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: productpage
spec:
hosts:
- "productpage"
gateways:
- your-gateway # 替换为你的 Gateway 名称
http:
- match:
- headers:
user-agent:
regex: ".*Mobile.*"
route:
- destination:
host: productpage
subset: v2
- route:
- destination:
host: productpage
subset: v1


# 解释:
# match:使用 headers 字段匹配 HTTP Header。这里将所有 User-Agent 包含 Mobile 字符串的请求路由到 v2 版本。

istio的核心功能

熔断

熔断的目的是在出现故障或异常情况时,对服务进行自动的限流和隔离,以保护整个系统的稳定性和可用性。

首先创建一个pod服务进行熔断测试。

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
60
61
62
63
64
65
66
67
68
69
70
#参考使用istio自带的yaml文件
[root@k8s-master ~]# cd istio-1.18.2/samples/httpbin/
[root@k8s-master httpbin]# cat httpbin.yaml //该yaml文件创建了sa账号,service及pod

apiVersion: v1
kind: ServiceAccount
metadata:
name: httpbin
---
apiVersion: v1
kind: Service
metadata:
name: httpbin
labels:
app: httpbin
service: httpbin
spec:
ports:
- name: http
port: 8000
targetPort: 80
selector:
app: httpbin
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: httpbin
spec:
replicas: 1
selector:
matchLabels:
app: httpbin
version: v1
template:
metadata:
labels:
app: httpbin
version: v1
spec:
serviceAccountName: httpbin
containers:
- image: /kong/httpbin
imagePullPolicy: IfNotPresent
name: httpbin
ports:
- containerPort: 80


#创建
[root@k8s-master httpbin]# kubectl apply -f httpbin.yaml
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created

[root@k8s-master httpbin]# kubectl get pods -owide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
httpbin-65975d4c6f-2nvnw 2/2 Running 0 14s 10.244.194.97 k8s-worker1 <none> <none>

[root@k8s-master httpbin]# kubectl get sa
NAME SECRETS AGE
httpbin 0 18s
[root@k8s-master httpbin]# kubectl get sve

[root@k8s-master httpbin]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.98.237.91 <none> 8000/TCP 29s

[root@k8s-master httpbin]# kubectl describe svc httpbin | grep -i endpoints
Endpoints: 10.244.194.97:80 //确认该service已成功代理到新创建的httpbin的pod

配置熔断规则

对上方创建的pod服务进行配置熔断规则:

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
[root@k8s-master ~]# vim destinationrule.yaml
apiVersion: /v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin #host指定service的名称,通过service找到它代理的后端pod
trafficPolicy: #配置熔断的策略
connectionPool: #配置熔断的连接池
tcp: #指定限制tcp协议连接的数量
maxConnections: 1 #指定每个目标服务最大连接数为1(目标就是上方定义的hosts指定的service所代理的后端pod)
http: #指定http协议的连接数
http1MaxPendingRequests: 1 #每个连接最大的挂起请求数为1,超过即阻塞
maxRequestsPerConnection: 1 #每个连接最大的请求数为1,每个连接最多只能处理一个请求
outlierDetection: #检测目标服务的异常情况(目标就是上方定义的hosts指定的service所代理的后端pod)
consecutiveGatewayErrors: 1 #访问目标服务的时候,目标会返回结果,如果返回错误大于等于1,则认为它异常
interval: 1s #探测时间为1秒探测一次
baseEjectionTime: 3m #定义重新连接时间,探测异常之后,三分钟内不进行连接
maxEjectionPercent: 100 #100表示,只要探测一次失败,就将连接100%拒绝


#创建
[root@k8s-master ~]# kubectl apply -f destinationrule.yaml
destinationrule./httpbin created

[root@k8s-master ~]# kubectl get DestinationRule
NAME HOST AGE
httpbin httpbin 8s

创建客户端模拟请求

使用istio工具自带的yaml文件创建一个客户端进行模拟访问httpbin pod服务,从而测试熔断的规则是否生效。

该pod中运行的服务是fortio,fortio是专门对网站进行压测的。通过该工具调用httpbin服务从而测试熔断规则。

创建fortio
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
60
61
62
63
64
65
66
67
68
69
70
71
#进入到目标路径
[root@k8s-master ~]# cd istio-1.18.2/samples/httpbin/sample-client
#找到如下yaml文件
#该文件定义了一个servic,一个deployment控制器,该控制器管理一个pod副本,使用的镜像就是fortio/fortio:latest_release

[root@k8s-master sample-client]# vim fortio-deploy.yaml
apiVersion: v1
kind: Service
metadata:
name: fortio
labels:
app: fortio
service: fortio
spec:
ports:
- port: 8080
name: http
selector:
app: fortio
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: fortio-deploy
spec:
replicas: 1
selector:
matchLabels:
app: fortio
template:
metadata:
annotations:
# This annotation causes Envoy to serve cluster.outbound statistics via 15000/stats
# in addition to the stats normally served by Istio. The Circuit Breaking example task
# gives an example of inspecting Envoy stats via proxy config.
/config: |-
proxyStatsMatcher:
inclusionPrefixes:
- "cluster.outbound"
- "cluster_manager"
- "listener_manager"
- "server"
- "cluster.xds-grpc"
labels:
app: fortio
spec:
containers:
- name: fortio
image: fortio/fortio:latest_release
imagePullPolicy: Always
ports:
- containerPort: 8080
name: http-fortio
- containerPort: 8079
name: grpc-ping


#创建
[root@k8s-master sample-client]# kubectl apply -f fortio-deploy.yaml
service/fortio created
deployment.apps/fortio-deploy created

[root@k8s-master sample-client]# kubectl get pods
NAME READY STATUS RESTARTS AGE
fortio-deploy-77fd47587d-xc2rb 1/2 Running 0 5s
httpbin-65975d4c6f-2nvnw 2/2 Running 0 40m

[root@k8s-master sample-client]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fortio ClusterIP 10.108.185.62 <none> 8080/TCP 14s
httpbin ClusterIP 10.98.237.91 <none> 8000/TCP 40m
模拟访问请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 #测试请求一次,如下显示正常
[root@k8s-master sample-client]# kubectl exec fortio-deploy-77fd47587d-xc2rb -c fortio -- /usr/bin/fortio curl http://httpbin:8000/get

{"ts":1731640199.687434,"level":"info","r":1,"file":"scli.go","line":122,"msg":"Starting","command":"Φορτίο","version":"1.66.5 h1:WTJzTGOA12YWZSM5g43602lH+GOsmP3eKHXLnuRW4vs= go1.22.7 amd64 linux","go-max-procs":2}
{"args":{},"headers":{"Host":"httpbin:8000","User-Agent":"fortio.org/fortio-1.66.5","X-B3-Parentspanid":"5d47d415a942dccc","X-B3-Sampled":"1","X-B3-Spanid":"66b7ec176aec3566","X-B3-Traceid":"ff306f65ca8d3fe35d47d415a942dccc","X-Envoy-Attempt-Count":"1","X-Forwarded-Client-Cert":"By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=492b9ebc73979709b0651c1233de23aa512178f3199b2d3fab9bf9ede8c38232;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"},"origin":"127.0.0.6","url":"http://httpbin:8000/get"}
HTTP/1.1 200 OK
server: envoy
date: Fri, 15 Nov 2024 03:09:59 GMT
content-type: application/json
content-length: 516
access-control-allow-origin: *
access-control-allow-credentials: true
x-envoy-upstream-service-time: 19


参数解释:
#exec // 进入到目标pod fortio (自己的fortio名称)
#-c //指定pod中的容器 fortio
#-- /usr/bin/fortio curl http://httpbin:8000/get //使用该命令请求httpbin
1
2
3
4
5
6
7
8
9
10
11
12
13
#测试多次请求,测试熔断中设置的http协议访问规则最大请求数及并发数等规则是否生效。
[root@k8s-master sample-client]# kubectl exec -it fortio-deploy-77fd47587d-xc2rb -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get

参数解释:
#-c 2 //发起两个并发连接
#-qps 0 //每秒请求数为0,零表示不限制,测试请求过程中,每秒内都以最大的速率去请求。
#-n 20 //总的请求数为20次,配合-c 2 ,总共发起20次请求,两个并发。(也就是一个连接请求20次,并发两个)
#-loglevel Warning //定义日志级别为Warning


#如下图中的状态码可以看到Code 200 的返回了85.0 %,Code 503 的返回了15.0 %,
#可解释为,第一个请求20次的连接来了后就进行了相应,但是在20次请求中还没响应完成,第二个并发的请求就来了,导致了阻塞。
#由此可见熔断规则确实生效。(每个服务器不同,响应速度也不同,所以返回状态码的百分比也不相同)

超时

在多台服务器互相请求时为了避免等待的响应时间过长,从而堆积大量的请求阻塞了自身服务,造成雪崩的影响,这种情况下可以可以使用istio的“超时”功能。

如A服务,请求B服务,可以设置超时等待时间,如请求时超过了这个设置的等待时间,那么将不再等待请求,直接返回请求超时错误。

创建测试超时使用的pod

这里使用了nginx、tomcat镜像创建pod,并创建svc代理这两个pod。

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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#使用deployment控制器创建nginx pod副本
[root@k8s-master ~]# vim timeout-deploy-nginx.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
replicas: 1
selector:
matchLabels:
server: nginx
app: web
template:
metadata:
name: nginx
labels:
server: nginx
app: web
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent

#创建
[root@k8s-master ~]# kubectl apply -f timeout-deploy-nginx.yaml
deployment.apps/nginx created

[root@k8s-master ~]# kubectl get pods | egrep -i "name|nginx"
NAME READY STATUS RESTARTS AGE
nginx-9d6c758bb-98l49 2/2 Running 0 23s
[root@k8s-master ~]#


#使用deployment控制器创建tomcat pod副本
[root@k8s-master ~]# vim timeout-deploy-tomcat.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
replicas: 1
selector:
matchLabels:
server: tomcat
app: web
template:
metadata:
name: tomcat
labels:
server: tomcat
app: web
spec:
containers:
- name: tomcat
image: tomcat
imagePullPolicy: IfNotPresent

#创建
[root@k8s-master ~]# kubectl apply -f timeout-deploy-tomcat.yaml
deployment.apps/tomcat created

[root@k8s-master ~]# kubectl get pods | egrep -i "name|nginx|tomcat"
NAME READY STATUS RESTARTS AGE
nginx-9d6c758bb-98l49 2/2 Running 0 4m14s
tomcat-5fb5bd59cd-86jwr 2/2 Running 0 8s


#创建servic 代理nginx及tomcat pod。
[root@k8s-master ~]# vim timeout-nginx-tomcat-service.yaml

apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
server: nginx
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
server: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
protocol: TCP


#创建
[root@k8s-master ~]# kubectl apply -f timeout-nginx-tomcat-service.yaml
service/nginx-svc created
service/tomcat-svc created

[root@k8s-master ~]# kubectl get svc | egrep -i "nginx|tomcat"
istio-pod-nginx ClusterIP 10.96.179.74 <none> 80/TCP 6d21h
nginx-svc ClusterIP 10.97.48.223 <none> 80/TCP 24s
tomcat-svc ClusterIP 10.111.194.112 <none> 8080/TCP 24s

配置超时

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
#创建pod
[root@k8s-master ~]# vim timeout-virtual-nginx-tomcat.yaml
apiVersion: /v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts: #指定svc
- nginx-svc #指定作用在nginx-svc,相当于作用的是它代理的nginx的pod
http:
- route:
- destination: #指定超时时间
host: nginx-svc #指定目标
timeout: 2s #指定超时时间2秒
---
apiVersion: /v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc #同上,这里指定的是tomcat-svc
http:
- fault: #模拟注入配置故障规则
delay: #配置延迟响应的规则
percentage: #指定延迟流量的百分比
value: 100 #这里指定100,表示100%的流量都会收到延迟响应
fixedDelay: 10s #指定延迟响应时间为10秒
route:
- destination: #指定访问的目标主机
host: tomcat-svc

#创建
[root@k8s-master ~]# kubectl apply -f timeout-virtual-nginx-tomcat.yaml
virtualservice./nginx-vs created
virtualservice./tomcat-vs created

[root@k8s-master ~]# kubectl get VirtualService | egrep -i "nginx|tomcat"
nginx-vs ["nginx-svc"] 21s
tomcat-vs ["tomcat-svc"] 21s

nginx配置反向代理tomcat

1
2
3
4
5
6
#进入到nginx  pod配置反向代理,将nginx请求代理到tomcat
[root@k8s-master ~]# kubectl exec -it nginx-9d6c758bb-98l49 -c nginx -- /bin/sh
/ # vi /etc/nginx/conf.d/default.conf //修改配置文件增加两行内容,如下图片所示:proxy_pass http://tomcat-svc:8080;proxy_http_version 1.1;
/ # nginx -t
/ # nginx -s reload //重启nginx
/ # exit

测试超时规则

这里使用了busybox镜像运行pod去访问nginx测试超时规则是否生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@k8s-master ~]# kubectl run busybox --image=busybox --restart=Never --rm -it --image-pull-policy=IfNotPresent -- sh
If you don\'t see a command prompt, try pressing enter.
/ # time wget -q -O - http://nginx-svc:80
wget: server returned error: HTTP/1.1 504 Gateway Timeout
//这里的504超时,是因为超时规则设置的是最多等待两秒。tomcat配置的是延迟十秒,超过两秒则等待超时

Command exited with non-zero status 1
real 0m 2.01s //这里显示的是实际执行时间。(2秒)
user 0m 0.00s
sys 0m 0.00s


#测试tomcat响应时间
/ # time wget -q -O - http://tomcat-svc:8080 | tail -n 3
real 0m 10.01s //这里可看到,执行了十秒才响应。
user 0m 0.00s
sys 0m 0.00s

故障注入和重试

“重试”,顾名思义,当第一次连接失败之后,可以根据配置的重试规则次数,在连接失败之后重新连接几次

根据上方测试”超时“时使用的nginx代理tomcat为例,测试“故障注入和重试”:

1
2
3
4
#因为需要配置“重试”规则,需要将上方测试“超时”时创建的VirtualService资源删除
[root@k8s-master ~]# kubectl delete -f timeout-virtual-nginx-tomcat.yaml
virtualservice. "nginx-vs" deleted
virtualservice. "tomcat-vs" deleted

配置重试规则并注入故障规则

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
#配置重试规则
[root@k8s-master ~]# vim timeout-virtual-nginx-tomcat-02.yaml
apiVersion: /v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination: #指定作用的目标
host: nginx-svc
retries:
attempts: 3 #指定重试次数
perTryTimeout: 2s #指定每两秒重试一次
---
apiVersion: /v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault: #模拟注入故障规则
abort:
percentage: #指定访问流量百分比
value: 100
httpStatus: 503 #指定请求返回错误结果为503
route:
- destination: #指定目标
host: tomcat-svc

#创建
[root@k8s-master ~]# kubectl apply -f timeout-virtual-nginx-tomcat-02.yaml
virtualservice./nginx-vs created
virtualservice./tomcat-vs created

[root@k8s-master ~]# kubectl get VirtualService | egrep -i "nginx|tomcat"
nginx-vs ["nginx-svc"] 12s
tomcat-vs ["tomcat-svc"] 12s

测试重试规则

继续使用busybox镜像进行访问测试:

1
2
3
4
5
6
7
8
9
10
11
[root@k8s-master ~]# kubectl run busybox --image=busybox --restart=Never --rm -it --image-pull-policy=IfNotPresent -- sh
If you don\'t see a command prompt, try pressing enter.

/ # wget -q -O - http://nginx-svc:80 //访问测试
wget: server returned error: HTTP/1.1 503 Service Unavailable
/ # exit

#观察nginx pod中的istio代理容器日志查看是否发生了重试
[root@k8s-master ~]# kubectl logs -f nginx-9d6c758bb-98l49 -c istio-proxy

#日志内容如下图所示,重试了四次,且每次都返回了503(首次访问失败并按照配置的重试规则进行重新访问了3次,一共4次)
Thank you for your accept. mua!
-------------本文结束感谢您的阅读-------------