Akemi

Istio微服务网格

2024/05/06

如果出现无法载图的情况,请检查与github的连通性

概述

Istio是一个开源的服务网格,为kubernetes和其他平台上的微服务架构提供统一的、灵活的网络通信和管理方式。

具有 代理注入,服务发现,负载均衡,流量管理,故障恢复和安全性功能
注入Envoy代理到没一个微服务的pod中;
将流量动态转发到可用的实例,支持多种服务发现机制;
根据不同需求进行流量分发与负载均衡;
支持流量切分,A/B测试,金丝雀发布;

功能:

1.快速失败返回:目标服务不可用时不再尝试等待请求,而是快速返回错误,避免长时间等待
2.熔断:在服务的通信中防止故障扩散,不会影响到整个应用程序
3.恢复:先使用一小部分流量,如果正常了会逐步关闭熔断

Istio架构与组件

控制节点组件为istiod,istiod包括Pilot、citadel、galley:
1.Pilot从服务注册中心获取服务和实例信息,并为Envoy生成配置。Envoy根据Pilot的信息,完成具体流量的转发

2.citadel负责Istio的身份和凭据管理;用于为服务生成和分发TLS证书

3.galley是Istio的配置管理组件,负责验证、分发配置给其他组件。当有配置信息出现变化时,同步给其他组件。

数据节点组件Envoy Pilot-agent:
4.Envoy是Istio的代理容器,如果开启了Istio,在创建服务时会创建代理容器,与朱容器属于同个pod,代理进出pod的流量,并根据外部请求规则作用于主容器中

5.ingressgateway入口网关,作为整个网络的入口,所有外部请求都集中到入口网关,然后将其引导到内部服务

6.egressgateway出口网关,作为整个网络的出口

功能与原理

1.自动注入
创建pod时自动调用sidecar代理服务,自动将sidecar代理容器注入到pod中

2.流量拦截
通过设置iptables规则,envoy会拦截业务容器的入口和出口流量。
留出frontend服务的流量会被frontend服务侧的sidecar拦截,当流量到达forecast时,inbound流量被forecast服务侧的sidecar拦截

3.服务发现
服务发起方envoy调用控制组件Pilot的发现接口,得到forecast服务的各项实例地址

4.负载均衡

5.流量治理
envoy从Pilot中获取流量治理规则,根据不同特征,将不同流量分发到forecast服务的不同版本

6.访问安全
在frontend的envoy与forecast的envoy访问时,会进行加密

7.服务监测
frontend服务与forecast服务的访问都会连接mixer上报访问数据,mixer将数据转发给对应的监控后端

8.策略执行
通过mixer来控制服务之间的访问,进行速率控制等操作

9.外部访问
外部访问入口gateway,通过gateway访问frontend

Istio部署,开启与关闭

环境

k8s版本 1.28
Istio版本 1.21
安装需要的镜像:
docker.io/istio/pilot:1.21.0
docker.io/istio/proxyv2:1.21.0
可以直接拉取也可以在github上下载

安装

1
2
3
4
5
6
7
8
9
10
11
12
tar xf istio-1.21.0-linux-amd64.tar.gz
cd istio-1.21.0/
cp bin/istioctl /bin/
#安装istio
istioctl install --set profile=demo -y
#看网络条件,我直接一次性装完了,如果网络差可能需要先拉取docker镜像,再ctr导入镜像
安装模式profile=demo:适应生产环境,安装3个pod
profile=default:最小配置,仅包含istiod与ingressgateway(一般测试用
profile=minimal:最小化安装,仅包含istiod(一般测试用

#卸载istio命令
istioctl manifest generate --set profile=demo | kubectl delete -f -

关闭istio自动注入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
kubectl get ns --show-labels
NAME STATUS AGE LABELS
default Active 35d istio-injection=enabled,kubernetes.io/metadata.name=default
devlopment Active 8d kubernetes.io/metadata.name=devlopment
istio-system Active 7d2h kubernetes.io/metadata.name=istio-system
jenkins-k8s Active 9d kubernetes.io/metadata.name=jenkins-k8s
kube-node-lease Active 35d kubernetes.io/metadata.name=kube-node-lease
kube-public Active 35d kubernetes.io/metadata.name=kube-public
kube-system Active 35d kubernetes.io/metadata.name=kube-system
letsencrypt-staging Active 5d22h kubernetes.io/metadata.name=letsencrypt-staging
monitor-sa Active 31d kubernetes.io/metadata.name=monitor-sa

因为default ns下有istio-injection=enabled,
默认在defaultns下创建pod,就会自动注入代理容器

#关闭功能
kubectl label ns default istio-injection-

Istio使用——以bookinfo应用为例

bookinfo在线书店,是istio自带的一个案例
分为四个单独的微服务:
1.productpage会调用details和reviews两个微服务用来生成界面
2.details包含书籍信息
3.review包含书籍评论
4.ratings包含书籍评级信息

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
#为了让istio能自动注入sidecar,default的ns打上标签,istio-injection=enabled
kubectl label ns default istio-injection=enabled

#
cd /root/Istio/istio-1.21.0/samples/bookinfo/platform/kube
kubectl apply -f bookinfo.yaml

#创建网关与虚拟服务
/root/Istio/istio-1.21.0/samples/bookinfo/networking
kubectl apply -f bookinfo-gateway.yaml

#查看状态
kubectl get gateway
NAME AGE
bookinfo-gateway 35s

kubectl get virtualservice
NAME GATEWAYS HOSTS AGE
bookinfo ["bookinfo-gateway"] ["*"] 54s

#查看svc
kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egressgateway ClusterIP 10.102.255.76 <none> 80/TCP,443/TCP 64m
istio-ingressgateway LoadBalancer 10.107.22.5 <pending> 15021:31606/TCP,80:32510/TCP,443:32060/TCP,31400:32635/TCP,15443:31893/TCP 64m
istiod ClusterIP 10.105.99.16 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 64m

#
浏览器访问
http://apiserver:32510/productpage

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
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
创建两个pod,分别打上不同的标签
#创建canary v1 labels:apply=canary
labels:
app: v1
apply: canary

#创建canary v2 labels:apply=canary
labels:
app: v2
apply: canary

#创建service绑定apply=canary,将流量引入v1v2两个pod(默认轮询)
apiVersion: v1
kind: Service
metadata:
name: canary
labels:
apply: canary
spec:
selector:
apply: canary
ports:
- protocol: TCP
port: 80
targetPort: 80

#创建gateway,绑定istio=ingressgateway,表示接受发送给ingressgateway的流量
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: canary-gateway
spec:
selector:
istio: ingressgateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"

#创建virtualservice,创建路由,将通往canary-gateway的流量发给svc,并且指定权重
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: canary
spec:
hosts:
- "*"
gateways:
- canary-gateway
http:
- route:
- destination:
host: canary.default.svc.cluster.local
subset: v1
weight: 90 #权重
- destination:
host: canary.default.svc.cluster.local
subset: v2
weight: 10

#创建destination rule,给svc创建v1v2两条subnet
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: canary
spec:
host: canary.default.svc.cluster.local
subsets:
- name: v1
labels:
app: v1
- name: v2
labels:
app: v2

逐渐修改weight比例,将流量逐步向v2转移

熔断

所需镜像:docker.io/kong/httpbin

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
#创建httpbin的deployment
/root/istio/istio-1.21.0/samples/httpbin
kubectl apply -f httpbin.yaml
所用镜像:docker.io/kong/httpbin

#创建一个DestinationRule,熔断策略
cat > fuse-policy.yaml <<EOF
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: httpbin
spec:
host: httpbin #绑定httpbin的service
trafficPolicy: #策略
connectionPool: #熔断连接池,设置了两个
tcp: #限制tcp链接的数量
maxConnections: 1 #httpbin的最多并发1个连接
http: #限制http的连接数
http1MaxPendingRequests: 1 #每个连接最大挂起请求数
maxRequestsPerConnection: 1 #每个连接最大处理请求数
outlierDetection:
consecutiveGatewayErrors: 1 #错误1次网关错误即异常
interval: 1s #探测间隔
baseEjectionTime: 3m
maxEjectionPercent: 100 #100%拒绝连接
EOF
kubectl apply -f fuse-policy.yaml

#部署fortio客户端进行测试访问,fortio是一个专门对网站做压测的工具,可以对连接数 并发数进行测试
/root/istio/istio-1.21.0/samples/httpbin/sample-client
kubectl apply -f fortio-deploy.yaml
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
fortio ClusterIP 10.102.153.6 <none> 8080/TCP 28h
httpbin ClusterIP 10.97.84.16 <none> 8000/TCP 28h
kubectl get pods
NAME READY STATUS RESTARTS AGE
fortio-deploy-77fd47587d-mrfl9 2/2 Running 0 27h
httpbin-86b8ffc5ff-7mjmn 2/2 Running 0 28h

所用镜像:fortio/fortio:latest_release

#测试
kubectl exec fortio-deploy-77fd47587d-mrfl9 -c fortio \
-- /usr/bin/fortio curl http://httpbin:8000/get
返回状态码200,正常

kubectl exec fortio-deploy-77fd47587d-mrfl9 -c fortio \
-- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning \
http://httpbin:8000/get
-c 2: 指定并发连接数为 2。这表示在测试期间,将会模拟 2 个并发请求。
-qps 0: 指定每秒请求数为 0。这表示在测试期间,将以最大速率发送请求,即不限制每秒请求数。
-n 20: 指定总请求数为 20。这表示在测试期间,将发送总共 20 个请求

...
Code 200 : 14 (70.0 %)
Code 503 : 6 (30.0 %)
...

超时

在生产环境中经常会碰到由于调用方等待下游的响应过长,堆积大量的请求阻塞了自身服务,造成雪崩的情况,通过通过超时处理来避免由于无限期等待造成的故障,进而增强服务的可用性,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
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
nginx-deployment.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:1.14-alpine
imagePullPolicy: IfNotPresent

tomcat-deployment.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: docker.io/kubeguide/tomcat-app:v1
imagePullPolicy: IfNotPresent

nginx-tomcat-svc.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

virtual-tomcat.yaml 虚拟服务
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: nginx-vs
spec:
hosts:
- nginx-svc
http:
- route:
- destination:
host: nginx-svc
timeout: 2s
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: tomcat-vs
spec:
hosts:
- tomcat-svc
http:
- fault:
delay:
percentage:
value: 100
fixedDelay: 10s
route:
- destination:
host: tomcat-svc

应用案例pod文件
nginx-deployment.yaml tomcat-deployment.yaml
nginx-tomcat-svc.yaml

创建虚拟服务virtual-tomcat.yaml:
设置应用到nginx的svc,请求超时时间2s
设置应用到tomcat的svc,调用请求时,延迟10s

这种情况下一定会报错,用这种方法来手动模拟故障

进入容器修改nginx配置文件,将流量代理到svc上,流量会通过定义好的虚拟服务进入
在虚拟服务中添加相应规则,就可以防止下游响应时间过长的问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
kubectl get pods
NAME READY STATUS RESTARTS AGE
fortio-deploy-77fd47587d-mrfl9 2/2 Running 4 (54m ago) 30h
httpbin-86b8ffc5ff-7mjmn 2/2 Running 4 (54m ago) 31h
nginx-67dffc45d-nf2rh 2/2 Running 4 (54m ago) 63m
tomcat-659d5845d4-5fcpx 2/2 Running 4 (54m ago) 63m

#修改nginx的配置文件
kubectl exec -it nginx-67dffc45d-nf2rh -- sh
# vi /etc/nginx/conf.d/default.conf

location / {
proxy_pass http://tomcat-svc:8080;
proxy_http_version 1.1;
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
测试

#创建一个网络测试镜像busybox
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh

time wget -q -O - http://nginx-svc
wget: server returned error: HTTP/1.1 504 Gateway Timeout
Command exited with non-zero status 1
real 0m 2.00s
user 0m 0.00s
sys 0m 0.00s

time wget -q -O - http://tomcat-svc:8080
...超时

重试

Istio 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务,除非我们启动 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
kubectl delete -f virtual-tomcat.yaml

#
写一个用来重试的virtualservice
...
- route:
- destination:
host: nginx-svc
retries: #重试配置
attempts: 3 #表示失败了重试三次
perTryTimeout: 2s #手动请求间隔2s
...
http:
- fault: #模拟故障
abort:
percentage:
value: 100
httpStatus: 503 #设置返回为503
route: #目标服务
- destination:
host: tomcat-svc
...

kubectl apply -f virtual-attempt.yaml

#测试容器
kubectl run busybox --image busybox:1.28 --restart=Never --rm -it busybox -- sh

wget -q -O - http://nginx-svc
wget: server returned error: HTTP/1.1 503 Service Unavailable
#重试了三次

查看日志:
kubectl logs -f nginx-67dffc45d-nf2rh -c istio-proxy

补充————熔断、压测与性能评估原则

最佳实践

假设k8s集群有100个节点,每个节点是100vCPU、100g内存,基于deployment部署了3个pod,运行的服务是web服务,三个pod跑在不同的节点上,每个pod最多占用6g内存6vcpu,每个pod最多的请求数是100万,三个pod前端有个四层代理,通过istio熔断机制作用在三个pod前端的四层代理上,那熔断参数值如何设置?

1.maxConnections:

假设每个 Pod 最多支持 6 个 vCPU,可以设置 maxConnections 为 80(稍微小于节点的 CPU 核心数,考虑到其他系统进程的资源使用)。

2.http1MaxPendingRequests:

假设你的应用在正常负载情况下,每秒请求数在 1000 到 5000 之间,可以设置 http1MaxPendingRequests 为 500,以确保连接不会积压过多的请求。

3.maxRequestsPerConnection:

假设你的应用的响应时间在 10 毫秒左右,你可以设置 maxRequestsPerConnection 为 100,这样每个连接可以处理 100 个请求后再关闭。

请注意,以上数值仅供参考,实际设置需要根据你的应用特性和性能测试结果来确定。压力测试是一个迭代的过程,你可能需要多次测试和优化,找到最适合你应用的参数设置。

同时,还需要考虑 Istio 熔断参数的设置。你可以根据之前提到的测试结果和分析,根据实际情况设置 consecutiveGatewayErrors 和 interval 等参数,以实现对代理层的熔断保护。

参数设置

最终的参数设置是一个动态平衡的过程,需要结合多方面因素综合考虑。建议在测试环境中进行实际的压力测试和性能评估,以找到最优的参数配置,确保你的应用在高负载下能够稳定运行。

  1. maxConnections:TCP 连接数的最大值。它限制了单个 Pod 上的 TCP 连接数量。这个值需要根据你的 Web 服务的并发量和每个请求的连接数来确定。
  2. http1MaxPendingRequests:HTTP1 的最大挂起请求数。当超过这个数值时,新的请求将被拒绝,直到有请求处理完成。这个值也要根据你的 Web 服务的并发量和 HTTP1 的特性来确定。
  3. maxRequestsPerConnection:每个连接的最大请求数。当超过这个数值时,连接将被关闭,新的请求将使用新的连接。这个值可以用于限制长时间保持的连接。
  4. outlierDetection:异常检测参数。这个参数用于检测异常的流量,并触发熔断机制。以下是 outlierDetection 参数的两个属性:
  • consecutiveGatewayErrors:连续网关错误数。当连续出现这么多次网关错误时,熔断将会触发。
  • interval:检测的时间间隔。在这个时间间隔内进行异常检测。

针对具体的数值,取决于你的应用实际情况和性能测试的结果。一般来说,你需要进行压力测试和性能评估,观察系统在不同负载下的表现,然后逐步调整熔断参数,找到适合你应用的最佳数值。

压测和性能评估步骤

进行压力测试和性能评估是确保应用在不同负载下能够正常运行的关键步骤。这些测试有助于发现系统的瓶颈、性能问题和资源需求,以便做出相应的优化和调整。下面是进行压力测试和性能评估的一般步骤:

1.确定测试目标和场景:

  • 确定要测试的具体目标,例如检查服务的响应时间、并发连接数、吞吐量等。
  • 设计不同负载场景,包括正常负载和峰值负载,以及可能的异常情况。

2.配置测试环境:

  • 创建与生产环境尽可能相似的测试环境。这包括硬件、网络、操作系统、Kubernetes集群等。

3.选择合适的工具:

  • 选择适合的应用和测试需求的性能测试工具。一些常见的工具包括Apache JMeter、Vegeta、wrk、Siege等。

4.设置测试参数:

  • 针对不同的测试场景,设置合理的压力测试参数,包括请求频率、并发用户数、连接数等。

5.执行压力测试:

  • 运行压力测试工具,模拟不同负载场景,收集性能数据。

6.监控系统指标:

  • 在测试过程中,监控系统的各项指标,包括CPU利用率、内存使用、网络流量、响应时间等。

7.分析结果:

  • 根据测试结果,分析系统在不同负载下的表现。发现瓶颈、性能问题和资源瓶颈。

8.优化和调整:

  • 根据分析结果,进行优化和调整。可能需要调整Kubernetes资源配额、调整服务配置、进行代码优化等。

9.重复测试:

  • 如果进行了优化和调整,需要再次进行压力测试,以验证改进效果。

10.容灾测试(可选):

  • 在一定负载下,模拟节点故障或服务失效等情况,验证集群的容错能力和自愈能力。

11.综合评估:

  • 结合所有测试结果,综合评估系统的性能和稳定性,确保满足预期的负载和性能要求。

注意事项:

  • 在进行压力测试时,确保测试环境和生产环境隔离,以免对生产系统造成影响。
  • 选择适当的负载测试场景,覆盖典型的使用情况和预期的峰值负载。
  • 记录测试结果和分析过程,方便后续回溯和对比。
  • 压力测试应该在非高峰期进行,以免影响正常用户的体验。

原文作者:王盛

原文链接:https://akemi.zj.cn/2024/05/06/Istio/

发表日期:May 6th 2024, 3:22:00 pm

更新日期:February 20th 2025, 6:37:27 pm

版权声明:本文采用知识共享署名-非商业性使用 4.0 国际许可协议进行许可

CATALOG
  1. 1. 概述
  2. 2. Istio架构与组件
    1. 2.1. 功能与原理
  3. 3. Istio部署,开启与关闭
    1. 3.1. 环境
    2. 3.2. 安装
    3. 3.3. 关闭istio自动注入
  4. 4. Istio使用——以bookinfo应用为例
  5. 5. Istio灰度发布
  6. 6. 熔断
  7. 7. 超时
    1. 7.1. 配置文件
    2. 7.2. 测试
  8. 8. 重试
  9. 9. 补充————熔断、压测与性能评估原则
    1. 9.1. 最佳实践
    2. 9.2. 参数设置
    3. 9.3. 压测和性能评估步骤