K8S-服务网格Istio
- 未分类
- 25天前
- 26热度
- 0评论
K8S-服务网格Istio
云原生服务网格(Service Mesh)是一种专门设计用于管理微服务间通信的基础设施层,通常在云原生架构中用于提高服务间的可观察性、安全性和可靠性。服务网格通过代理(sidecar 模式)实现服务间通信的拦截和管理,而无需在服务本身中植入逻辑
Service Mesh 核心特性如下:
1、流量管理:负载均衡,动态分发流量,确保高可用。流量控制,基于策略的请求路由(如蓝绿部署、金丝雀发布)。故障处理,自动重试、超时、熔断等。
2、安全性:加密通信,实现服务间的 mTLS(双向传输层安全)。认证与授权,控制服务访问权限。
3、可观察性:日志、指标和追踪,集成 Prometheus、Grafana 等工具,提供服务间通信的详细视图。
4、服务治理:动态配置,支持在运行时更改策略。故障注入,用于测试系统的可靠性和容错性。
Service Mesh 包括数据平面和控制平面,数据平面负责处理服务之间的流量,通常由轻量级代理(如 Envoy)组成。Sidecar 模式是主流部署方式,将代理作为每个微服务的附属。控制平面负责管理数据平面,包括配置分发、策略管理和监控数据的收集。如 Istio 的 Pilot(路由配置)、Citadel(安全)、Galley(配置验证)。
常见的服务网格工具有 Istio、Linkerd、Envoy、Kuma 等。
Istio 东西流量管理(VirtualService)
在 Istio 中,东西流量管理 是指集群内服务之间的流量控制,通常通过配置 VirtualService 来实现。VirtualService 是 Istio 的核心资源之一,用于定义服务的路由规则,例如基于特定条件将流量引导到不同版本的服务,或实现蓝绿部署、金丝雀发布等高级流量管理功能。
VirtualService 是一个逻辑上的服务抽象,定义了流量的路由规则。它允许通过简单的配置实现复杂的服务通信需求。
VS的核心功能如下:
1、路由:基于服务版本、路径、头部等条件分流流量。
2、重试和超时:自动处理失败请求或设置请求超时时间。
3、故障注入:模拟延迟、错误等网络异常,用于测试系统的健壮性。
4、镜像流量:将流量副本发送到另一个服务版本进行测试。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: my-service
spec:
hosts: #VirtualService 的主机,即用户指定的目标或路由规则的目标,客户端向服务端发送请求时使用的一个或多个地址
- my-service.default.svc.cluster.local # 服务地址
http: # 路由规则配置,用来指定流量的路由行为,通过该处配置将 HTTP/1.1、HTTP/1.2、gRPC等流量发送到 hosts 字段指定的目标中
- match: # 路由匹配的条件,根据某些条件指定更加细粒度的路由
- headers:
request-user:
exact: caijx
- route: # 路由规则, destination字段指定了符合此条件的流量的实际目标地址
- destination:
host: my-service
subset: v1 # 路由到服务的 v1 版本
weight: 80
- destination:
host: my-service
subset: v2 # 路由到服务的 v2 版本
weight: 20
Istio细粒度流控(DestinationRule)
在 Istio 中,DestinationRule 是流量管理的重要资源,主要用于定义目标服务的具体路由策略,比如连接池设置、负载均衡策略、TLS 加密设置、子集(Subsets)定义等。通过与 VirtualService 配合,DestinationRule 实现了细粒度的流量控制。
DestinationRule 可以实现子集定义、负载均衡、连接池管理、故障处理和TLS 加密等功能。
属性 | VirtualService | DestinationRule |
---|---|---|
职责 | 定义流量的路由规则,决定如何转发流量 | 定义目标服务的行为,决定如何处理转发的流量 |
主要关注 | 流量路由规则,流量分配(基于请求头、路径) | 负载均衡策略、子集定义、连接池和熔断 |
操作层级 | 处理服务入口流量,匹配 HTTP/TCP 请求规则 | 处理到目标服务器的具体通信行为(如子集路由) |
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: my-service # DestinationRule 的名称,用于标识规则
spec:
host: my-service.default.svc.cluster.local # 目标服务的全限定域名(FQDN)
subsets: # 定义服务的多个版本(子集)
- name: v1 # 子集名称,用于路由匹配
labels:
version: v1 # 匹配目标 Pod 的标签 version=v1
- name: v2
labels:
version: v2 # 匹配目标 Pod 的标签 version=v2
trafficPolicy: # 定义流量管理策略
loadBalancer:
simple: LEAST_CONN # 使用最少连接数的负载均衡策略
connectionPool: # 连接池配置,限制连接数量和请求
http:
http1MaxPendingRequests: 100 # HTTP/1.1 最大挂起请求数
maxRequestsPerConnection: 10 # 每个连接的最大请求数,控制长连接生命周期
tcp:
maxConnections: 50 # TCP 最大并发连接数,限制资源消耗
outlierDetection: # 故障实例检测和驱逐配置
consecutiveErrors: 5 # 连续出现 5 次错误后,标记实例为不健康
interval: 10s # 健康检查的时间间隔
baseEjectionTime: 30s # 实例被驱逐后重新加入的等待时间
tls: # 配置服务间的 mTLS 加密
mode: ISTIO_MUTUAL # 使用 Istio 自动管理的双向 TLS 模式
Istio 南北流量管理(Gateway)
在 Istio 中,Gateway 为 HTTP/TCP 流量配置负载均衡器,最常见的是在网格的边缘的操作,以启用应用程序的入口流量。Istio 中 Gateway 分为 IngressGateway 和EgressGateway,分别管理进来的流量和出去的流量
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
name: my-gateway
spec:
selector:
istio: ingressgateway # 使用默认的 Istio Ingress Gateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "example.com" # 只接受匹配此域名的请求
Istio实践
Istio安装
官方文档以及版本的选型参考以下链接,推荐生产环境使用稳定版本,即最后一位版本号大于5
https://istio.io/latest/docs/releases/supported-releases/#support-status-of-istio-releases
注意:在安装之前请读者先参考官方文档,会给出两种安装方式,一种是会用 K8S Gateway进行安装,这种方式也是官方推荐并且未来流行的安装方式,另外一种是使用传统的 Istio API 进行安装,使用传统的 Gateway 和 VS。但是Istio的功能并没有全部适配 K8S 的 Gateway,所以为了后面实验的操作和讲解, 此处选择1.24.2的传统版本进行安装。
中文官网地址如下
https://istio.io/latest/zh/
安装最新版本的 Istio 并安装
[root@master-01 ~]# curl -L https://istio.io/downloadIstio | sh -
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 101 100 101 0 0 74 0 0:00:01 0:00:01 --:--:-- 74
100 5124 100 5124 0 0 2189 0 0:00:02 0:00:02 --:--:-- 16690
Downloading istio-1.24.2 from https://github.com/istio/istio/releases/download/1.24.2/istio-1.24.2-linux-amd64.tar.gz ...
Istio 1.24.2 download complete!
The Istio release archive has been downloaded to the istio-1.24.2 directory.
To configure the istioctl client tool for your workstation,
add the /root/istio-1.24.2/bin directory to your environment path variable with:
export PATH="$PATH:/root/istio-1.24.2/bin"
Begin the Istio pre-installation check by running:
istioctl x precheck
Try Istio in ambient mode
https://istio.io/latest/docs/ambient/getting-started/
Try Istio in sidecar mode
https://istio.io/latest/docs/setup/getting-started/
Install guides for ambient mode
https://istio.io/latest/docs/ambient/install/
Install guides for sidecar mode
https://istio.io/latest/docs/setup/install/
Need more information? Visit https://istio.io/latest/docs/
可以指定对应的架构和版本号进行安装,对应的变量可参考下面链接的脚本
curl -L https://istio.io/downloadIstio | ISTIO_VERSION=1.24.2 TARGET_ARCH=x86_64 sh -
https://raw.githubusercontent.com/istio/istio/master/release/downloadIstioCandidate.sh
切换到 Istio 文件包目录,samples目录包含样例应用,bin 目录包含 istioctl 客户端二进制文件,添加 istioctl 客户端路径到环境变量内
[root@master-01 ~]# cd istio-1.24.2/
[root@master-01 istio-1.24.2]# export PATH=$PWD/bin:$PATH
安装Istio,使用demo配置文件,里面包含了 Ingress 和 Egress 的配置。读者也可以参考官方文档选取其他的配置(注意:镜像为国外镜像,如果第一次安装拉取失败,请手动修改控制器里面的镜像地址)
[root@master-01 istio-1.24.2]# istioctl install --set profile=demo -y
|\
| \
| \
| \
/|| \
/ || \
/ || \
/ || \
/ || \
/ || \
/______||__________\
____________________
\__ _____/
\_____/
v Istio core installed ⛵️
v Istiod installed 🧠
v Ingress gateways installed 🛬
v Egress gateways installed 🛫
v Installation complete
安装完成后,会在 istio-system命名空间下创建对应的 Pod 和 Service
[root@master-01 istio-1.24.2]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istio-egressgateway-7f84f7d97d-fv857 1/1 Running 0 76s
istio-ingressgateway-5cd5465d86-5g2mm 1/1 Running 0 71s
istiod-57fc4b6cd6-6s5hr 1/1 Running 0 97s
[root@master-01 istio-1.24.2]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-egressgateway ClusterIP 10.96.210.113 <none> 80/TCP,443/TCP 85s
istio-ingressgateway LoadBalancer 10.96.7.215 <pending> 15021:32157/TCP,80:32604/TCP,443:31482/TCP,31400:30430/TCP,15443:32125/TCP 84s
istiod ClusterIP 10.96.29.135 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 116s
添加命名空间标签,指示 Istio 在署应用时自动注入 Envoy Sidecar 代理(注意:并非要在默认的命名空间下,可以指定其他的命名空间,但是部署的应用要在有对应标签的命名空间下才能自动注入 Sidecar )
[root@master-01 istio-1.24.2]# kubectl label namespace default istio-injection=enabled
namespace/default labeled
部署 Bookinfo 示例应用
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/platform/kube/bookinfo.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
查看在 default 命名空间下创建的 Pod 和 Service,可以通过观察到对应的 Pod 都被部署了 Istio Sidecar( READY 2/2 且 STATUS 为 Running)
[root@master-01 istio-1.24.2]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
details ClusterIP 10.96.228.70 <none> 9080/TCP 2m15s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 68d
productpage ClusterIP 10.96.55.24 <none> 9080/TCP 2m12s
ratings ClusterIP 10.96.190.222 <none> 9080/TCP 2m14s
reviews ClusterIP 10.96.168.254 <none> 9080/TCP 2m13s
[root@master-01 istio-1.24.2]# kubectl get pods
NAME READY STATUS RESTARTS AGE
details-v1-6cd6d9df6b-zjrt8 2/2 Running 0 3m32s
productpage-v1-57ffb6658c-56fnd 2/2 Running 0 3m28s
ratings-v1-794744f5fd-6pzvw 2/2 Running 0 3m31s
reviews-v1-67896867f4-2jlrx 2/2 Running 0 3m30s
reviews-v2-86d5db4bd6-7w6xn 2/2 Running 0 3m30s
reviews-v3-77947c4c78-q9fd5 2/2 Running 0 3m30s
执行以下命令通过检查响应中的页面标题查看应用是否在集群内运行且正在提供 HTML 页面
[root@master-01 istio-1.24.2]# kubectl exec "$(kubectl get pod -l app=ratings -o jsonpath='{.items[0].metadata.name}')" -c ratings -- curl -sS productpage:9080/productpage | grep -o "<title>.*</title>"
<title>Simple Bookstore App</title>
Bookinfo 应用已被部署但还不能从外部进行访问。 要使其能够被访问,需要创建 Istio Ingress Gateway, 将路径映射到网格边缘处的某个路由
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/networking/bookinfo-gateway.yaml
Warning: resource gateways/bookinfo-gateway is missing the kubectl.kubernetes.io/last-applied-configuration annotation which is required by kubectl apply. kubectl apply should only be used on resources created declaratively by either kubectl create --save-config or kubectl apply. The missing annotation will be patched automatically.
gateway.networking.istio.io/bookinfo-gateway configured
virtualservice.networking.istio.io/bookinfo created
检查配置是否正确
[root@master-01 istio-1.24.2]# istioctl analyze
v No validation issues found when analyzing namespace: default.
由于安装时,自动配置了 Ingress,在外部浏览器访问任意安装了 kube-proxy 的机器地址+ Ingress映射端口/productpage,刷新界面可以观察到星星图标会消失或者改变颜色
Istio 默认暴露了很多监控指标,比如请求数量统计、请求持续时间以及 Service 和工作 负载的指标,这些指标可以使用 Prometheus 进行收集,Grafana 进行展示。
Istio 内置了 Prometheus 和 Grafana 的安装文件,直接安装即可(也可以使用外置的 Prometheus 和 Grafana)
在安装 Kiali 时会自动安装上面所述的插件
[root@master-01 istio-1.24.2]# kubectl apply -f samples/addons
serviceaccount/grafana created
configmap/grafana created
service/grafana created
deployment.apps/grafana created
configmap/istio-grafana-dashboards created
configmap/istio-services-grafana-dashboards created
deployment.apps/jaeger created
service/tracing created
service/zipkin created
service/jaeger-collector created
serviceaccount/kiali created
configmap/kiali created
clusterrole.rbac.authorization.k8s.io/kiali created
clusterrolebinding.rbac.authorization.k8s.io/kiali created
service/kiali created
deployment.apps/kiali created
serviceaccount/loki created
configmap/loki created
configmap/loki-runtime created
clusterrole.rbac.authorization.k8s.io/loki-clusterrole created
clusterrolebinding.rbac.authorization.k8s.io/loki-clusterrolebinding created
service/loki-memberlist created
service/loki-headless created
service/loki created
statefulset.apps/loki created
serviceaccount/prometheus created
configmap/prometheus created
clusterrole.rbac.authorization.k8s.io/prometheus created
clusterrolebinding.rbac.authorization.k8s.io/prometheus created
service/prometheus created
deployment.apps/prometheus created
[root@master-01 istio-1.24.2]# kubectl rollout status deployment/kiali -n istio-system
Waiting for deployment "kiali" rollout to finish: 0 of 1 updated replicas are available...
deployment "kiali" successfully rolled out
通过循环命令持续访问网页,以便在kiali界面看到流量路径
[root@master-01 istio-1.24.2]# for i in $(seq 1 100); do curl -s -o /dev/null "http://192.168.132.169:32604/productpage"; done
查看 kiali 服务的 Service 并修改类型为 NodePort,通过浏览器访问 Kiali 仪表板(Prometheus和Grafana也是一样的方法)
[root@master-01 istio-1.24.2]# kubectl get service -n istio-system | grep kiali
kiali NodePort 10.96.197.75 <none> 20001:31763/TCP,9090:31403/TCP
单击左侧导航栏的 Traffic Graph按钮,可以观察到流量路径(注意右上方的时间),项目对应的功能的架构请参考官方文档
https://istio.ac.cn/latest/docs/examples/bookinfo/
此处给出完整的 Service 和 Pod 供读者参考
[root@master-01 istio-1.24.2]# kubectl get svc -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
grafana ClusterIP 10.96.238.159 <none> 3000/TCP 23h
istio-egressgateway ClusterIP 10.96.210.113 <none> 80/TCP,443/TCP 24h
istio-ingressgateway LoadBalancer 10.96.7.215 <pending> 15021:32157/TCP,80:32604/TCP,443:31482/TCP,31400:30430/TCP,15443:32125/TCP 24h
istiod ClusterIP 10.96.29.135 <none> 15010/TCP,15012/TCP,443/TCP,15014/TCP 24h
jaeger-collector ClusterIP 10.96.208.159 <none> 14268/TCP,14250/TCP,9411/TCP,4317/TCP,4318/TCP 23h
kiali NodePort 10.96.197.75 <none> 20001:31763/TCP,9090:31403/TCP 23h
loki ClusterIP 10.96.193.159 <none> 3100/TCP,9095/TCP 23h
loki-headless ClusterIP None <none> 3100/TCP 23h
loki-memberlist ClusterIP None <none> 7946/TCP 23h
prometheus ClusterIP 10.96.68.242 <none> 9090/TCP 23h
tracing ClusterIP 10.96.103.31 <none> 80/TCP,16685/TCP 23h
zipkin ClusterIP 10.96.140.244 <none> 9411/TCP 23h
[root@master-01 istio-1.24.2]# kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
grafana-7c69b5ff87-wfntd 1/1 Running 0 23h
istio-egressgateway-7f84f7d97d-fv857 1/1 Running 0 24h
istio-ingressgateway-5cd5465d86-5g2mm 1/1 Running 0 24h
istiod-57fc4b6cd6-6s5hr 1/1 Running 0 24h
jaeger-66f9675c7b-v9t4p 1/1 Running 0 23h
kiali-665944f699-4rmwk 1/1 Running 0 23h
loki-0 0/2 Pending 0 23h
prometheus-f754dc469-sfnpj 2/2 Running 1 (28m ago) 23h
Istio 流量治理实践
Istio 实现灰度部署
将 reviews 的所有流量指向 v1 版本,此时需要通过 DestinationRule 将 reviews 分成三个版本
[root@master-01 istio-1.24.2]# vim reviews-destinationrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews
subsets:
- name: v1
labels:
version: v1 # subset v1 指向具有 version=v1 的 Pod
- name: v2
labels:
version: v2 # subset v2 指向具有 version=v2 的 Pod
- name: v3
labels:
version: v3 # subset v3 指向具有 version=v3 的 Pod
[root@master-01 istio-1.24.2]# kubectl create -f reviews-destinationrule.yaml
destinationrule.networking.istio.io/reviews created
[root@master-01 istio-1.24.2]# kubectl get -f reviews-destinationrule.yaml
NAME HOST AGE
reviews reviews 7s
配置 VirtualService 将所有流量指向 reviews 的 v1 版本(在samples/bookinfo/networking/virtual-service-all-v1.yaml配置文件内有完整版本,但是只有reviews服务有版本区分,所以使用简单版本的配置即可)
[root@master-01 istio-1.24.2]# vim virtual-service-all-v1.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1
[root@master-01 istio-1.24.2]# kubectl create -f virtual-service-all-v1.yaml
virtualservice.networking.istio.io/reviews created
[root@master-01 istio-1.24.2]# kubectl get -f virtual-service-all-v1.yaml
NAME GATEWAYS HOSTS AGE
reviews ["reviews"] 6s
此时刷新浏览器不再显示星级,并且在kiali 界面可以观察到流量只会转发到reviews-v1的 Pod 上
修改 VirtualService,将 20%的流量导向 v2 版本
[root@master-01 istio-1.24.2]# vim virtual-service-20v2-80v1.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v1 # 将 80%流量指向 v1
weight: 80 # 只需要配置一个 weight 参数即可
- destination:
host: reviews
subset: v2 # 将 20%流量指向 v2
weight: 20
[root@master-01 istio-1.24.2]# kubectl replace -f virtual-service-20v2-80v1.yaml
virtualservice.networking.istio.io/reviews replaced
浏览器刷新界面,可以观察到有部分流量已经转移到 reviews-v2容器上,并且kiali界面已经有流量指向
当测试完成时,确认v2版本没有问题,可以修改Virtualservice,将所有流量切换到v2版本
[root@master-01 istio-1.24.2]# vim virtual-service-all-v2.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- route:
- destination:
host: reviews
subset: v2
Istio 实现 AB 测试
AB 测试(A/B Testing)是一种对照实验方法,主要用于比较两种或多种版本的效果,从而确定哪种版本能够实现更好的目标,例如提高点击率、转化率或用户体验。
通过Istio的请求头匹配功能可以实现该测试,读者可以参考官网链接
https://istio.ac.cn/latest/docs/tasks/traffic-management/request-routing/
修改 reviews 的 VirtualService,将 jason 用户指向 v3,其他用户依旧使用 v2 版本
[root@master-01 istio-1.24.2]# vim review-v3jason.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews
http:
- match:
- headers: # 匹配请求头
end-user: # 匹配请求头的 key 为 end-user
exact: jason # value 为 jason
route:
- destination:
host: reviews
subset: v3 # 匹配到 end-user=jason 路由至 v3 版本
- route:
- destination:
host: reviews
subset: v2 # 其余的路由至 v2 版本
[root@master-01 istio-1.24.2]# kubectl apply -f review-v3jason.yaml
virtualservice.networking.istio.io/reviews created
重新刷新bookinfo界面,可以观察到星星的颜色没有变化,单击右上角的 Sign in按钮进行登录,账号为jason,密码为任意输入。
登录后,可以观察到星星的颜色发生变化,代表了匹配到jason用户,并且流量指向v3版本
Istio 地址重写和重定向
关于重定向的内容,读者可以参考以下链接
https://istio.io/latest/docs/reference/config/networking/virtual-service/#HTTPRedirect
访问bookinfo.test.com/blog,跳转到blog.caijxlinux.work/580,修改virtualservice服务配置文件,添加跳转的链接(注意:此处的.spec.hosts字段为*号,可以匹配IP但是不能匹配域名,并且redirect和route不能同时存在)
[root@master-01 istio-1.24.2]# cat samples/bookinfo/networking/bookinfo-gateway.yaml
...省略部分输出...
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
- uri:
exact: /blog
redirect:
uri: /580
authority: blog.caijxlinux.work
# route:
# - destination:
# host: productpage
# port:
# number: 9080
[root@master-01 istio-1.24.2]# kubectl replace -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway replaced
virtualservice.networking.istio.io/bookinfo replaced
此时,访问192.168.132.169/blog,会自动跳转到博客地址
[root@master-01 istio-1.24.2]# curl -I 192.168.132.169:32144/blog
HTTP/1.1 301 Moved Permanently
location: http://blog.caijxlinux.work/580
date: Sat, 11 Jan 2025 09:07:55 GMT
server: istio-envoy
transfer-encoding: chunked
配置Istio 地址重写,将根路径修修改为/productpage(未配置地址重写前,访 问根路径会限制 404 错误)
[root@master-01 istio-1.24.2]# curl -I 192.168.132.169:32144
HTTP/1.1 404 Not Found
date: Sat, 11 Jan 2025 09:16:23 GMT
server: istio-envoy
transfer-encoding: chunked
修改virtualservice服务配置文件
[root@master-01 istio-1.24.2]# cat samples/bookinfo/networking/bookinfo-gateway.yaml
...省略部分输出...
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "*"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
- uri:
prefix: /
rewrite:
uri: /productpage
# - uri:
# exact: /blog
# redirect:
# uri: /580
# authority: blog.caijxlinux.work
route:
- destination:
host: productpage
port:
number: 9080
[root@master-01 istio-1.24.2]# kubectl replace -f samples/bookinfo/networking/bookinfo-gateway.yaml
gateway.networking.istio.io/bookinfo-gateway replaced
virtualservice.networking.istio.io/bookinfo replaced
再次访问
[root@master-01 istio-1.24.2]# curl -I 192.168.132.169:32144
HTTP/1.1 200 OK
server: istio-envoy
date: Sat, 11 Jan 2025 09:18:43 GMT
content-type: text/html; charset=utf-8
content-length: 15072
vary: Cookie
x-envoy-upstream-service-time: 356
Istio 负载均衡算法
Istio 原生支持多种负载均衡算法,比如 ROUND_ROBIN、LEAST_CONN、RANDOM 等。假如一个应用存在多个副本(Pod),可以使用上述算法对多个 Pod 进行定制化的负载均衡配置
策略 | 描述 |
---|---|
ROUND_ROBIN | 默认,轮询算法,将请求依次分配给每一个实例 |
LEAST_CONN | 最小连接数,随机选择两个健康实例,将请求分配成两个中连接数最少的那个 |
RANDOM | 随机算法,将请求随机分配给其中一个实例 |
PASSTHROUGH | 将连接转发到调用者请求的原始 IP 地址,而不进行任何形式的负载均衡 |
首先使用之前的for循环访问 bookinfo 的首页,之后查看 Kiali 中 reviews 的流量分配(删除之前的流量策略,由于作者的虚拟机有问题,所以端口修改了)
[root@master-01 istio-1.24.2]# kubectl delete -f review-v3jason.yaml
virtualservice.networking.istio.io "reviews" deleted
[root@master-01 ~]# for i in $(seq 1 100); do curl -s -o /dev/null "http://192.168.132.169:32144/productpage"; done
在 kiali 界面的Traffic Graph选项卡,单击 Display选项卡的下拉箭头,勾选 Traffic Distribution 按钮,随后可以观察到流量基本上是平均到三个版本上
修改负载算法改成RANDOM
[root@master-01 ~]# kubectl edit destinationrules.networking.istio.io reviews
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
creationTimestamp: "2025-01-11T09:35:02Z"
generation: 2
name: reviews
namespace: default
resourceVersion: "1667013"
uid: 0472ba0f-b9b7-4169-8d46-c11de4a8a5a9
spec:
trafficPolicy:
loadBalancer:
simple: RANDOM
host: reviews
subsets:
- labels:
version: v1
name: v1
- labels:
version: v2
name: v2
...省略部分输出...
此处刷新kiali界面,可以观察到流量的分配并不平衡
Istio 熔断
在 Istio 中,熔断是一种用于提升服务稳定性和容错能力的机制。通过熔断,Istio 能够在服务发生故障或延迟增大时,快速采取措施避免问题扩散,从而保护系统整体的健康。
熔断类似于电路中的断路器。当某个服务调用失败率过高或延迟过长时,Istio 会中断后续的请求,避免持续向出问题的服务发送流量。这不仅保护了故障服务本身,还能防止其他服务因为等待超时而受到影响。
创建httpbin服务,以供后面的熔断测试
[root@master-01 istio-1.24.2]# kubectl apply -f samples/httpbin/httpbin.yaml
serviceaccount/httpbin created
service/httpbin created
deployment.apps/httpbin created
创建一个目标规则, 在调用 httpbin 服务时应用熔断设置
[root@master-01 istio-1.24.2]# vim dr-httpbin.yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: httpbin # 定义 DestinationRule 的名称,用于标识该规则
spec:
host: httpbin # 指定目标服务的主机名,这里的目标服务是 httpbin
trafficPolicy: # 配置服务的流量策略
connectionPool: # 连接池配置,限制并发连接数和排队请求数
tcp:
maxConnections: 1 # TCP 连接的最大并发数,限制为 1,避免服务资源耗尽
http:
http1MaxPendingRequests: 1 # HTTP/1.x 的最大排队请求数,限制为 1
maxRequestsPerConnection: 1 # 每个连接的最大请求数,限制为 1,有助于强制短连接
outlierDetection: # 异常检测配置,识别和隔离不健康的实例
consecutive5xxErrors: 1 # 连续 1 次返回 5xx 错误时,触发熔断
interval: 1s # 健康检查的时间间隔为 1 秒
baseEjectionTime: 3m # 实例被移除后的恢复时间为 3 分钟
maxEjectionPercent: 100 # 最大移除实例的百分比,这里设置为 100%,意味着可以移除所有实例
[root@master-01 istio-1.24.2]# kubectl create -f dr-httpbin.yaml
destinationrule.networking.istio.io/httpbin created
[root@master-01 istio-1.24.2]# kubectl get -f dr-httpbin.yaml
NAME HOST AGE
httpbin httpbin 31s
创建客户端程序以发送流量到 httpbin 服务。这是一个名为 Fortio 的负载测试客户端, 它可以控制连接数、并发数及发送 HTTP 请求的延迟。 通过 Fortio 能够有效的触发前面在 DestinationRule 中设置的熔断策略
[root@master-01 istio-1.24.2]# kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml
service/fortio created
deployment.apps/fortio-deploy created
等待 fortio 容器启动后,获取 fortio 容器 id
[root@master-01 istio-1.24.2]# kubectl get pods -l app=fortio -o 'jsonpath={.items[0].metadata.name}'
fortio-deploy-b6757cbbb-x8z6c
[root@master-01 istio-1.24.2]# export FORTIO_POD=$(kubectl get pods -l app=fortio -o 'jsme}')h={.items[0].metadata.na
登入客户端 Pod 并使用 Fortio 工具调用 httpbin 服务。-curl 参数表明发送一次调用(状态码为200代表应用创建正常)
[root@master-01 istio-1.24.2]# kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio curl -quiet http://httpbin:8000/get
{
"args": {},
"headers": {
"Host": [
"httpbin:8000"
],
"User-Agent": [
"fortio.org/fortio-1.66.5"
],
"X-Envoy-Attempt-Count": [
"1"
],
"X-Forwarded-Client-Cert": [
"By=spiffe://cluster.local/ns/default/sa/httpbin;Hash=e9fc4f56adc59ff796f839de52687ad57bb9cd19fe8fc25586304aa284be8f4a;Subject=\"\";URI=spiffe://cluster.local/ns/default/sa/default"
],
"X-Forwarded-Proto": [
"http"
],
"X-Request-Id": [
"cf54ba8e-269c-982b-acdb-c25c9b15d6d2"
]
},
"method": "GET",
"origin": "127.0.0.6:53603",
"url": "http://httpbin:8000/get"
}
HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-origin: *
content-type: application/json; charset=utf-8
date: Sun, 12 Jan 2025 11:22:43 GMT
content-length: 621
x-envoy-upstream-service-time: 18
server: envoy
在 DestinationRule 配置中,定义了 maxConnections: 1 和 http1MaxPendingRequests: 1。 这些规则意味着,如果并发的连接和请求数超过一个,在 istio-proxy 进行进一步的请求和连接时,后续请求或连接将被阻止。发送并发数为 2 的连接(-c 2),请求 20 次(-n 20)
可以观察到有14次的成功请求和6次的失败请求,此时失败比例并不算太高
[root@master-01 istio-1.24.2]# kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://httpbin:8000/get
{"ts":1736680994.376799,"level":"info","r":1,"file":"logger.go","line":290,"msg":"Log level is now 3 Warning (was 2 Info)"}
Fortio 1.66.5 running at 0 queries per second, 2->2 procs, for 20 calls: http://httpbin:8000/get
Starting at max qps with 2 thread(s) [gomax 2] for exactly 20 calls (10 per thread + 0)
{"ts":1736680994.396221,"level":"warn","r":24,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":0,"run":0}
{"ts":1736680994.414937,"level":"warn","r":25,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":1,"run":0}
{"ts":1736680994.423820,"level":"warn","r":24,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":0,"run":0}
{"ts":1736680994.475054,"level":"warn","r":24,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":0,"run":0}
{"ts":1736680994.487317,"level":"warn","r":25,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":1,"run":0}
{"ts":1736680994.498695,"level":"warn","r":24,"file":"http_client.go","line":1151,"msg":"Non ok http code","code":503,"status":"HTTP/1.1 503","thread":0,"run":0}
Ended after 144.519096ms : 20 calls. qps=138.39
Aggregated Function Time : count 20 avg 0.013857322 +/- 0.01062 min 0.001071431 max 0.040938298 sum 0.277146443
# range, mid point, percentile, count
>= 0.00107143 <= 0.002 , 0.00153572 , 15.00, 3
> 0.002 <= 0.003 , 0.0025 , 20.00, 1
> 0.006 <= 0.007 , 0.0065 , 30.00, 2
> 0.007 <= 0.008 , 0.0075 , 35.00, 1
> 0.008 <= 0.009 , 0.0085 , 40.00, 1
> 0.009 <= 0.01 , 0.0095 , 45.00, 1
> 0.01 <= 0.011 , 0.0105 , 50.00, 1
> 0.012 <= 0.014 , 0.013 , 55.00, 1
> 0.014 <= 0.016 , 0.015 , 65.00, 2
> 0.016 <= 0.018 , 0.017 , 70.00, 1
> 0.018 <= 0.02 , 0.019 , 75.00, 1
> 0.02 <= 0.025 , 0.0225 , 85.00, 2
> 0.025 <= 0.03 , 0.0275 , 90.00, 1
> 0.03 <= 0.035 , 0.0325 , 95.00, 1
> 0.04 <= 0.0409383 , 0.0404691 , 100.00, 1
# target 50% 0.011
# target 75% 0.02
# target 90% 0.03
# target 99% 0.0407506
# target 99.9% 0.0409195
Error cases : count 6 avg 0.0053160085 +/- 0.005407 min 0.001071431 max 0.015010544 sum 0.031896051
# range, mid point, percentile, count
>= 0.00107143 <= 0.002 , 0.00153572 , 50.00, 3
> 0.002 <= 0.003 , 0.0025 , 66.67, 1
> 0.01 <= 0.011 , 0.0105 , 83.33, 1
> 0.014 <= 0.0150105 , 0.0145053 , 100.00, 1
# target 50% 0.002
# target 75% 0.0105
# target 90% 0.0144042
# target 99% 0.0149499
# target 99.9% 0.0150045
# Socket and IP used for each connection:
[0] 5 socket used, resolved to 10.96.40.126:8000, connection timing : count 5 avg 0.0003572168 +/- 0.0001682 min 0.000210291 max 0.000682692 sum 0.001786084
[1] 3 socket used, resolved to 10.96.40.126:8000, connection timing : count 3 avg 0.00027368067 +/- 3.221e-05 min 0.000244674 max 0.000318596 sum 0.000821042
Connection time (s) : count 8 avg 0.00032589075 +/- 0.0001404 min 0.000210291 max 0.000682692 sum 0.002607126
Sockets used: 8 (for perfect keepalive, would be 2)
Uniform: false, Jitter: false, Catchup allowed: true
IP addresses distribution:
10.96.40.126:8000: 8
Code 200 : 14 (70.0 %)
Code 503 : 6 (30.0 %)
Response Header Sizes : count 20 avg 171.85 +/- 112.5 min 0 max 246 sum 3437
Response Body/Total Sizes : count 20 avg 678.85 +/- 286.6 min 241 max 867 sum 13577
All done 20 calls (plus 0 warmup) 13.857 ms avg, 138.4 qps
提高并发量和请求次数,可以观察到被熔断的次数增长到了20次
[root@master-01 istio-1.24.2]# kubectl exec "$FORTIO_POD" -c fortio -- /usr/bin/fortio load -c 3 -qps 0 -n 30 -loglevel Warning http://httpbin:8000/get
...省略部分输出...
IP addresses distribution:
10.96.40.126:8000: 21
Code 200 : 10 (33.3 %)
Code 503 : 20 (66.7 %)
Response Header Sizes : count 30 avg 81.9 +/- 115.8 min 0 max 246 sum 2457
Response Body/Total Sizes : count 30 avg 449.56667 +/- 295 min 241 max 867 sum 13487
All done 30 calls (plus 0 warmup) 9.831 ms avg, 295.2 qps
查询 istio-proxy 状态以了解更多熔断详情(upstream_rq_pending_overflow 值 21,这意味着,目前为止已有 26 个调用被标记为熔断)
[root@master-01 istio-1.24.2]# kubectl exec "$FORTIO_POD" -c istio-proxy -- pilot-agent request GET stats | grep httpbin | grep pending
cluster.outbound|8000||httpbin.default.svc.cluster.local;.circuit_breakers.default.remaining_pending: 1
cluster.outbound|8000||httpbin.default.svc.cluster.local;.circuit_breakers.default.rq_pending_open: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local;.circuit_breakers.high.rq_pending_open: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local;.upstream_rq_pending_active: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local;.upstream_rq_pending_failure_eject: 0
cluster.outbound|8000||httpbin.default.svc.cluster.local;.upstream_rq_pending_overflow: 26
cluster.outbound|8000||httpbin.default.svc.cluster.local;.upstream_rq_pending_total: 25
Istio 注入延迟故障
在 Istio 中,注入延迟故障是一种用于测试服务性能和容错能力的重要功能。通过故意增加请求的延迟,模拟真实场景中的网络抖动或下游服务响应缓慢的情况,帮助开发者识别潜在问题并优化系统
运行以下命令来初始化应用程序版本路由,此时流量路径如下
productpage → reviews:v2 → ratings(针对 jason 用户)
productpage → reviews:v1(其他用户)
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/networking/virtual-service-all-v1.yaml
virtualservice.networking.istio.io/productpage created
virtualservice.networking.istio.io/reviews created
virtualservice.networking.istio.io/ratings created
virtualservice.networking.istio.io/details created
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtualservice.networking.istio.io/reviews configured
为了测试微服务应用程序 Bookinfo 的弹性,将为用户 jason 在 reviews:v2 和 ratings 服务之间注入一个 7 秒的延迟。 这个测试将会发现一个故意引入 Bookinfo 应用程序中的 BUG。注意 reviews:v2 服务对 ratings 服务的调用具有 10 秒的硬编码连接超时。 因此,尽管引入了 7 秒的延迟,我们仍然期望端到端的流程是没有任何错误的
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/networking/virtual-service-ratings-test-delay.yaml
virtualservice.networking.istio.io/ratings configured
[root@master-01 istio-1.24.2]# cat samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ratings # VirtualService 的名称,用于标识该规则
spec:
hosts:
- ratings # 指定目标服务的主机名,这里是 'ratings'
http:
- match:
- headers:
end-user:
exact: jason # 匹配请求头中 'end-user' 为 'jason' 的请求
fault:
delay:
percentage:
value: 100.0 # 为匹配的请求注入 100% 的延迟
fixedDelay: 7s # 固定延迟时间为 7 秒
route:
- destination:
host: ratings # 将请求路由到 'ratings' 服务
subset: v1 # 目标是 'ratings' 服务的 v1 子集(Subset),用于细化流量控制
- route:
- destination:
host: ratings # 默认情况下,将请求路由到 'ratings' 服务
subset: v1 # 默认流量也路由到 v1 子集
通过浏览器打开 bookinfo 界面,在不使用 jason用户登录时,一切正常,但是以用户 jason 登录到 /productpage 页面。Bookinfo 主页在大约 7 秒钟加载完成并且没有错误。 但是,出现了一个问题:Reviews 部分显示了错误消息
Sorry, product reviews are currently unavailable for this book.
通过 F12按钮,进行调试,可以看到/productpage 页面加载实际上用了大约 6 秒
按照预期,引入的 7 秒延迟不会影响到 reviews 服务,因为 reviews 和 ratings 服务间的超时被硬编码为 10 秒。 但是,在 productpage 和 reviews 服务之间也有一个 3 秒的硬编码的超时,再加 1 次重试,一共 6 秒。 结果,productpage 对 reviews 的调用在 6 秒后提前超时并抛出错误了
解决方法可以增加 productpage 与 reviews 服务之间的超时或降低 reviews 与 ratings 的超时
reviews 服务的 v3 版本已经修复了这个问题。 reviews:v3 服务已将 reviews 与 ratings 的超时时间从 10 秒降低为 2.5 秒,因此它可以兼容(小于)下游 productpage 请求的超时时间,读者可以使用流量转移的方法进行测试。此处由于是实验环境,所以直接修改jason用户的流量转发到v3版本,此时重新访问界面,虽然延迟一样,但已经不会产生错误了
[root@master-01 istio-1.24.2]# vim samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
...省略部分输出...
- match:
- headers:
end-user:
exact: jason
route:
- destination:
host: reviews
subset: v3
...省略部分输出...
[root@master-01 istio-1.24.2]# kubectl apply -f samples/bookinfo/networking/virtual-service-reviews-test-v2.yaml
virtualservice.networking.istio.io/reviews configured