Istio 服务网格:架构、部署与精细化流量治理
本文从服务网格的设计动机出发,依次说明 Istio 的架构与工作模式、核心资源、安装与运维方式,并以 Bookinfo 为主线演示流量发布、灰度、A/B 测试、负载均衡、熔断、故障注入、超时与重试。
服务网格背景
为什么要用服务网格
应用架构演变:单体应用 -- 微服务 -- 函数即服务
- 单体应用发展到微服务带来的问题:
- 服务间通信复杂:各个服务之间通过接口调用其他服务
- 流量精细化管理很难:比如想实现金丝雀发布
- 服务间安全通信难:双向TLS加密需要自己实现
- 多语言环境统一治理困难:Java服务怎么自动发现python服务等
- 跨服务间依赖管理困难:B服务挂掉,可能影响上游A服务
-
可观测性不足:链路调用可追踪性不足
-
为了解决上述问题,可以采用SpringCloud框架、Nacos框架等解决服务发现。但是也有问题:
- 一是k8s已经提供了这些功能,再在k8s中用springCloud属于套娃。
- 对于开发人员,需要手动维护微服务之间的调用、负载均衡、服务发现、熔断降级、动态路由等功能。这些都需要写代码,然而都不属于业务逻辑,严重影响开发效率。
-
springCloud和Nacos都是原生支持Java,但是对其他语言的支持性不好。这对于多语言环境很不友好。
-
为了解决上述问题,引入了服务网格:
- 把上述流量治理的功能下沉到了基础设施。开发人员只需要聚焦自己的业务逻辑就行了。
服务网格
SeriviceMesh有Buoyant公司CEO William Morgan发起,目标位解决微服务之间的复杂链路问题。
ServiceMesh将程序开发的网络功能和程序本身解耦,网络功能下沉到基础架构。
由服务网格实现服务之间的负载均衡等功能,并且除了网络功能外,也提供了其他更高级的功能,比如:全链路加密、监控、链路追踪等。
服务网格最常用的架构就是一个服务对应一个sidecar proxy。
核心功能
- 负载均衡
服务间访问可以自定义轮询、最小连接数等负载均衡算法。
- 服务发现
服务上下线,流量会自动做接入和切断
- 熔断降级
下游服务故障之后,上游服务会自动降级,避免发生微服务雪崩
- 动态路由
灰度、蓝绿发布
- 故障注入
用来测试服务韧性,模拟某个微服务的故障,测试其他服务的正常运行情况
- 错误重试
网络抖动时,提供重试功能。谨慎使用,避免幂等性问题。
- 安全通信
网格内的服务可以实现全链路加密,开箱即用
- 语言无关
服务网格代理与应用语言无关。
产品对比
Linkerd
- Buoyant公司在2016年率先开源的高性能网络代理程序。是服务网格的鼻祖,标志着Service Mesh时代的开始。
- 配置和管理比较复杂。
Envoy
- 高性能服务网格程序,为云原生设计。但是他并不是一款完整的服务网格产品,只是个网络代理程序。
- Istio和Kuma属于比较完整的服务网格程序,是基于Envoy开发的。
Kuma
- 由Kong开发并提供支持,是一个通用的现代服务网格控制平面。基于Envoy构建。
Istio
- Istio受Google、IBM、Lyft等公司的支持和推广,于2017年5月发布。底层为Envoy。
- 因为有大厂支持和背书,是现在服务网格产品的首选。
- 很多云计算大厂的k8s产品带的服务网格功能,底层也是接入的istio。
Istio 功能与架构
参考文档
Github地址:istio/istio
详解文章:Istio详解 - 掘金
核心功能
Istio是一个开源的服务网格(Service Mesh)产品,专为微服务架构设计,用于透明的管理微服务间的通信、安全、监控和流量策略。
在 Sidecar 模式下,Istio 通过 Envoy 拦截并控制服务间流量,将复杂的微服务治理从业务代码中剥离并下沉到基础设施层,使开发者更专注于业务逻辑。Ambient 模式则以节点级 Ztunnel 承担 L4 能力,并按需引入 Waypoint 提供 L7 治理。
以下是Istio的一些基本特性:
- 代理注入:Istio使用Envoy作为其数据面代理,通过注入Envoy代理到每个微服务的Pod中,实现对流量的控制和管理。这种代理注入的方式无需修改应用代码,提供了一种非侵入式的部署方式。(部署好istio,会自动在创建的pod里面注入一个sidecar envoy容器)
- 服务发现:Istio通过在代理中集成服务注册和发现机制,实现对微服务实例的自动发现和路由。它能够动态地将流量转发到可用的服务实例,并支持多种服务发现的机制
- 负载均衡:Istio 提供轮询、最小请求、随机和故障感知等策略,并可同时治理 L4 与 L7 流量。
- 流量管理:Istio可以实现对流量的灵活管理和控制,支持流量切分、A/B测试、金丝雀发布等高级流量管理功能。它可以帮助开发人员更好地控制和管理微服务架构中的流量。
- 故障恢复:Istio提供了故障恢复机制,包括超时控制、重试、断路器和熔断等。它能够自动检测和处理微服务中的故障,并提供弹性和可靠性。
- 安全性:Istio提供了丰富的安全功能,包括双向TLS流量加密(mTLS)、身份认证和授权、访问控制(用的比较少,开发者还是更愿意在程序内部处理认证逻辑)等。它可以通过自动注入代理,对服务间的通信进行加密和验证,提供了更高层次的安全保障。
- 集群出入口流量管理:入口流量,可以代替ingress-controller提供外部访问入口;出口流量,可以让集群出口流量固定到某一个出口出去。
流量管理
熔断
- 熔断是一种故障保护机制,用于在服务之间的通信中防止故障扩散,并提供更好的容错能力。在微服务架构中,一个应用通常由许多小型的、相互协作的服务组成。当某个服务发生故障或变得不可用时,如果不采取措施,可能会导致连锁反应,影响到整个系统的可用性。熔断机制旨在解决这个问题,其核心思想是在服务之间设置阈值和超时时间,并对请求进行监控。当服务的错误率或响应时间超过预设的阈值时,熔断器会打开,拒绝向该服务发送更多请求,并快速失败返回错误,而不是等待超时。
- 应用场景
- 快速失败返回: 当目标服务不可用时,不再尝试等待请求超时,而是快速返回错误,从而避免资源浪费和潜在的长时间等待。
- 故障隔离: 熔断机制阻止故障扩散,使问题局限在出现故障的服务,而不会影响到整个应用程序。
- 恢复机制: 熔断器会定期尝试发起一些请求到目标服务,以检查其是否已经恢复。如果服务恢复正常,则熔断器会逐渐关闭,允许流量再次流向目标服务。
-
自动重试: 一旦目标服务恢复,熔断器会逐渐允许一部分流量通过,如果没有再次出现问题,会逐渐恢复到正常状态,否则继续保持熔断状态。
-
在高并发情况下,如果请求数量达到一定极限(可以自己设置阈值),超出了设置的阈值,断路器会自动开启服务保护功能,通过服务降级的方式返回一个友好的提示给客户端。假设当10个请求中,有10%失败时,熔断器就会打开,此时再调用此服务,将会直接返回失败,不再调远程服务。直到10s之后,重新检测该触发条件,判断是否把熔断器关闭或者继续打开。
超时
- 在 Kubernetes(K8s)集群中结合 Istio,可以使用 Istio 的流量管理功能来控制服务之间的请求超时。超时是指在一定时间内,如果某个请求没有得到及时响应,就会被认为是超时。通过设置请求超时时间,可以对服务之间的通信进行控制,确保请求在合理的时间内得到响应,避免请求无限期地等待导致资源浪费或影响整体系统的响应性能。
Istio 的超时控制允许你为每个服务之间的请求设置最大的等待时间。当某个请求在指定的超时时间内没有得到响应时,Istio 会终止该请求并返回一个错误响应给客户端。这样可以防止请求在后端服务长时间等待,从而避免请求积压,同时提高系统的稳定性和可用性。
重试
- 重试机制就是如果调用服务失败,Envoy 代理尝试连接服务的最大次数。而默认情况下,Envoy 代理在失败后并不会尝试重新连接服务。
架构总览

Istio从逻辑上分为数据平面和控制平面:
-
控制平面:负责管理和配置数据平面的流量策略。管理员创建 Istio 资源后,控制平面会把资源转换为代理可理解的配置并下发。Istio 1.5 起以
istiod作为统一控制平面;早期版本中的 Pilot、Citadel、Galley、Mixer 等职责已经合并、替代或移除。 -
数据平面:
- 由一组以Sidecar方式部署的智能代理容器组成。这些代理承载并控制微服务之间的所有网络通信,管理入口和出口流量,类似于一线员工。
- Sidecar 一般和业务容器运行在一个pod里,来劫持业务应用容器的流量,并接受控制面组件的控制,同时会向控制面输出日志、跟踪及监控数据。
- 数据平面在Istio 1.22版本后,分为了Sidecar和Ambient两种模式:
- Sidecar模式:为集群中启动的pod部署一个Envoy代理,或者为在虚拟机上运行的服务并行创建一个Envoy代理。
- Ambient模式:在每个节点上启动四层代理Ztunnel,也可以在每个命名空间启动一个Envoy(waypoint)。出现这种模式是因为sidecar也需要占用资源,pod量上去之后,大量的sidecar也要占用很多资源。这种模式在节点上启动一个代理,这个代理故障会影响整个节点的流量。
Sidecar 与 Ambient 工作模式
| 对比项 | 对比维度 | Sidecar | Ambient |
|---|---|---|---|
| 核心架构 | 代理部署方式 | 每个pod注入一个Envoy Sidecar容器 | 分层部署: L4:每个节点部署一个Ztunnel代理 L7:每个ns部署一个或多个Waypoint代理 |
| 流量管理 | 通过iptables/IPVS规则劫持pod进出流量 | 四层由Ztunnel处理,七层由Waypoint处理 | |
| 覆盖范围 | 所有注入Sidecar的pod | 默认纳入所有pod,无需添加annotation(灵活性较差) | |
| 故障可用性 | 只影响某个故障的pod | 影响当前节点或当前空间的所有服务(影响较大) | |
| 资源开销 | 代理数量 | 每个pod一个Envoy | Ztunnel:每个节点一个代理 Wayponit:通常一个ns一个或多个 |
| 内存/CPU消耗 | 较高(也要看开启了多少sidecar) | 较低(也要看实际使用量) | |
| 启动延迟 | pod启动时需要等待Sidecar就绪 | Pod启动无需等待代理,延迟更低 | |
| 性能对比 | 调用延迟 | 每个请求经过两次Envoy代理 | 四层经过Ztunnel,七层经过Waypoint。(跨ns、跨节点时,经过多跳Ztunnel和Waypoint,延迟可能更多) |
Sidecar 是“每个 Pod 一个全功能代理”,Ambient 是“L4 默认覆盖、L7 按需引入”的分层代理。两者不是简单的新旧替代关系,应根据功能、资源成本和迁移风险选择。
性能与成本边界
L4 相比 L7 的资源节省幅度取决于协议、连接模型和策略复杂度。原始测试材料给出的区间为:CPU 约 20%~60%、P99 延迟约 10%~40%、内存约 15%~40%;这些是特定场景的观测区间,不能当作通用承诺。短连接越多,或路由匹配、镜像、重试、WASM 等 L7 策略越复杂,L7 代理成本通常越明显。
“完全零复制”并不现实
代理执行治理逻辑需要读取数据,mTLS 加解密也有 CPU 成本,跨进程数据路径无法完全共享内存。可优化的方向是少解析(L4 优先)、少策略(只启用必要能力)和少链路(避免不必要的镜像与过滤器)。
选型与迁移
- 适合优先评估 Ambient:服务数量大、Sidecar 常驻成本明显,大量流量只需要 L4 安全与连通能力。
- 适合继续使用 Sidecar:深度依赖复杂 L7 能力、当前架构已长期稳定,或缺少充分的迁移和回归验证窗口。
- 推荐采用分域、分批、可回滚的混合迁移:低风险域 → 中风险域 → 核心域;先让 L4 跑稳,再按需引入 Waypoint。
- 迁移前后统一观察 P99、5xx、CPU/内存,并为核心链路保留回滚路径。
做选型前先回答三个问题:业务需要多少 L7 治理;主要瓶颈是资源成本还是稳定性;团队是否具备分批迁移和可回滚验证能力。
参考来源:Istio Sidecar vs Ambient:不是“谁先进”,而是“谁更省、谁更稳、谁更适合你现在”
Istio 组件
控制平面
Pilot
Pilot主要用于监听API Server,动态获取集群中的svc和endpoint信息,将配置的路由规则、负载均衡策略转换为Envoy可理解的配置,下发到各个Sidecar中。

Citadel(历史组件职责)
-
Citadel负责Istio中的身份和凭据管理,提供安全相关功能。它用于为服务生成和分发TLS证书,以实现服务之间的安全通信。
-
Citadel可以被视为团队中的保密专员。它负责确保团队成员之间的通信是安全的,别人无法窃听或者假冒。Citadel会为每个队员提供一个保密的通信渠道,确保他们之间的交流是私密的,就像用密码和密钥加密信息一样。

Galley(历史组件职责)
- Galley是Istio的配置管理组件,负责验证、转换和分发配置给其他Istio组件。它监听Kubernetes的配置更改,例如Service、Deployment等,根据规则和策略生成Istio所需的配置,并将其提供给Pilot和其他组件。
- Gallery使用Mesh Configuration Protocol和其他组件进行配置交互。
- Galley可以被看作是团队中的文件管理员。它负责管理团队中所有的文件和信息,确保每个队员都能得到正确的信息和文件。当有新的文件产生或者文件发生变化时,Galley会及时通知团队中的每个成员,确保大家都使用的是最新的文件,不会出现信息不同步的问题。
数据平面
Envoy
-
Envoy是Istio中的代理,pod开启了istio功能,会在pod里自动注入Envoy sidecar容器,它负责处理服务之间的所有网络通信,拦截并转发所有的HTTP、TCP和gRPC流量。Envoy提供强大的流量控制和管理功能,如路由、重试、超时和故障注入等。
-
Envoy和主容器同属于一个Pod,共享网络和命名空间,Envoy代理进出Pod的流量,并将流量按照外部请求的规则作用于主容器中。
-
Envoy可以看作是服务之间的守护者。它像一个中间人一样,坐在每个服务旁边(就像每个队员身边都有一个保镖一样)。它负责处理服务之间的所有信息传递,确保信息传送得又快又准确。如果有请求从一个服务发出,Envoy会帮它找到正确的目标服务并将请求送达过去。它还能处理各种不同类型的请求,就像精通各种语言的翻译一样。

组件调用关系

- 自动注入:Kubernetes在创建Pod时调用Sidecar代理服务,自动将Sidecar代理容器(也叫做envoy容器)注入到Pod中。
- 流量拦截:通过设置iptables规则,Envoy拦截业务容器的入口和出口流量,应用程序感知不到Sidecar代理容器的存在。上图中,流出frontend服务的流量会被 frontend服务侧的 sidecar拦截,而当流量到达forecast容器时,Inbound流量被forecast 服务侧的sidecar拦截。
- 服务发现:服务发起方的 Envoy 调用控制面组件 Pilot 的服务发现接口获取目标服务的实例列表。上图中,frontend 服务侧的 Envoy 通过 Pilot 的服务发现接口得到forecast服务各个实例的地址。
- 负载均衡:服务发起方的Envoy根据配置的负载均衡策略选择服务实例,并连接对应的实例地址。上图中,数据面的各个Envoy从Pilot中获取forecast服务的负载均衡配置,并执行负载均衡动作。
- 流量治理:Envoy 从 Pilot 中获取配置的流量规则,在拦截到 Inbound 流量和Outbound 流量时执行治理逻辑。上图中, frontend 服务侧的 Envoy 从 Pilot 中获取流量治理规则,并根据该流量治理规则将不同特征的流量分发到forecast服务的v1或v2版本。
- 访问安全:在服务间访问时通过双方的Envoy进行双向认证和通道加密,并基于服务的身份进行授权管理。上图中,Pilot下发安全相关配置,在frontend服务和forecast服务的Envoy上自动加载证书和密钥来实现双向认证,其中的证书和密钥由另一个管理面组件 Citadel维护。
- 服务监测:数据面代理生成指标、访问日志和追踪信息,并交给对应的可观测性后端。早期架构使用 Mixer 汇聚遥测;新版本已把相关能力移入代理和控制平面扩展机制。
- 策略执行:代理依据控制平面下发的策略执行访问控制、限流等逻辑。早期版本可通过 Mixer 对接策略后端;新版本不再依赖 Mixer。
- 外部访问:在网格的入口处有一个Envoy扮演入口网关的角 色。上图中,外部服务通过Gateway访问入口服务 frontend,对 frontend服务的负载均衡和一些流量治理策略都在这个Gateway上执行。
Istio 核心资源
DestinationRule
目标规则,将服务划分为多个版本(子集),同时可以对不同版本进行配置负载均衡和连接池等策略。
使用场景:
- 版本划分:根据标签划分同一个服务的不同版本(使用灰度发布的时候会用到,v1/v2两个版本)
- 负载均衡策略:支持配置各种负载均衡算法(如轮询、随机、最小链接数等)
- 熔断器:支持配置最大连接数、熔断等
VirtualService
Istio 路由规则的核心,用于控制流量走向。和 Ingress 类似,支持 HTTP、gRPC、TCP 等协议。
控制南北流量:可以声明一个域名实现集群外访问。与Ingress类似。
控制东西流量:通常和DestinationRule结合实现更细粒度的流量分配。比如灰度发布。
主要应用场景:
- 灰度发布:支持基于比例的流量分配
- A/B测试:支持基于请求头、URI、权重等条件的流量分配
- 重试:支持错误重试、故障注入、链接超时等策略
Gateway
Istio集群的出入口网关,处理对外的流量。通常和VirtualService结合实现内外流量的统一治理。
主要应用场景:
- 端口监听:可根据协议指定对外暴露的端口
- TLS:可以根据域名证书提供HTTPS访问
- 域名:可以根据域名进行路由转发
- 出口管控:可以将出口的流量固定从EgressGateway的服务中代理出去
IngressGateway
- ingressgateway是Istio中的一个特殊网关,它作为整个网格的入口,接收外部请求,并将它们引导到内部的服务。
- 可以将它比作一个大门保安,负责接收外部人员的访问请求,然后根据配置的规则将请求分发给网格内部的服务。
- 可以类比为ingress-nginx controller。在本地实验环境部署中,本地域名+ingressgateway svc的高位端口访问到集群服务。
EgressGateway
- egressgateway是Istio中的另一个特殊网关,它负责处理网格内部服务对集群外部服务的访问请求。
- 可以将它看作是一个网格内部的出口,负责将内部服务需要访问的外部服务请求发送到外部。
核心资源逻辑架构

- DestinationRule:定义服务子集和流量策略,路由的最终目标。
- VirtualService:路由规则的核心,控制流量去向。
- Gateway:管理外部流量入口和出口,与VS协同实现内外流量统一治理。(只是声明对外暴露哪些域名和端口,实际路由转发规则是VS定义的)
三者可以单独使用也可以配合使用。
以上三种资源不是实际存在的,只是一些配置,Istio拿到这些资源,翻译成Envoy认识的配置,实际本质上起作用的还是Envoy、IngressGateway。
核心资源定义
DestinationRule
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: bookinfo-ratings
spec:
host: ratings.prod.svc.cluster.local # 路由规则的目标。客户端向服务端发送请求时用的地址。一般是写svc FQDN
trafficPolicy: # 针对这一个svc,配置流量规则配置
loadBalancer:
simple: LEAST_REQUEST # 最小请求算法
subsets: # 版本划分
- name: v3 # 自己起一个版本名称
labels:
version: v3
trafficPolicy: # 还可以对不同版本的服务做配置,这里的会覆盖掉外面的trafficPolicy
loadBalancer:
simple: ROUND_ROBIN # 轮询算法
VirtualService
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: ProductPage
namespace: nsA
spec:
hosts:
# 路由规则的目标,客户端向服务端发动请求时使用的地址。
# 如果是管理南北流量,写域名;管理东西流量,写svc的FQDN
- bookinfo.com
gateways:
# 管理南北流量,写当前域名绑定的gateway的名称。
# 管理东西流量,可以不用写
- my-gateway
http: # 配置七层代理规则 - 某个路径路由到哪个服务
- match:
- uri:
prefix: /productpage/v1/
route:
- destination:
host: productpage-v1.nsA.svc.cluster.local
# 请求匹配到bookinfo.com/productpage/v1/,就走上面的svc
# 没匹配到,就走这个默认的svc。下面的默认配置也可以不写。
- route:
- destination:
host: productpage.nsA.svc.cluster.local
Gateway
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: my-gateway
namespace: nsA
spec:
selector: # 选择运行此网关配置的istio ingress gateway pod(一般一个集群内装一个ingress gateway)
app: my-gateway-controller
servers:
- port:
name: http
number: 80
protocol: HTTP
hosts:
- "bookinfo.com"
推荐给每一个ns创建一个Gateway,单独管理这个ns里面的服务暴露的域名。
不推荐把所有的域名全放在一个Gateway资源里面,这样翻译出来的Envoy配置文件会变得很大。
生产环境高可用架构
回顾Ingress Controller的高可用架构:ingress Controller的pod所在的宿主机暴露80/443端口,前端有个负载均衡器LB(F5、SLB、LVS、HAProxy等),购买的公网域名绑定到LB的IP上。LB配置80/443端口,解析到ingress-conrtoller的节点的80/443上,ingress-controller再把流量代理到后端svc-pod。
Istio Gateway 架构
对于istio也是类似的:

Istio Gateway和ingress-controller一样,也是有一个端口在宿主机上暴露,这个端口是内网访问的入口。
服务发布到公网,需要在前端LB上配置IP或者代理,指向后端的istio gateway的端口号,由istio gateway再代理到后端服务。
与 Ingress Controller 的选型
istio gateway和ingress controller功能一样,实际使用中用哪个?
在功能层面,istio gateway完全覆盖ingress controller的功能(反之则不行)。所以建议网关直接用istio gateway。
Istio 安装与部署
版本与兼容性
官网版本支持表:Istio Supported Releases
github release:Releases - istio/istio
使用 istioctl 安装
Istio自带istioctl工具,用来操作istio。
#首先下载Istio的安装包:
wget https://github.com/istio/istio/releases/download/1.27.0/istio-1.27.0-linux-amd64.tar.gz
#解压后,将Istio的客户端工具istioctl,移动到/usr/local/bin 目录下:
tar xf istio-1.27.0-linux-amd64.tar.gz
cd istio-1.27.0 && mv bin/istioctl /usr/local/bin/
istioctl version
Helm 安装
参考:Istio Helm 安装文档、GitHub Releases、Artifact Hub - base、Artifact Hub - istiod、Artifact Hub - gateway。以下以 1.27.1 为示例版本:
helm repo add istio https://istio-release.storage.googleapis.com/charts
helm repo update
# 如需离线保存 Chart
helm pull istio/base --version 1.27.1
helm pull istio/istiod --version 1.27.1
helm pull istio/gateway --version 1.27.1
# 安装顺序:CRD/base -> control plane -> gateway
helm upgrade --install istio-base istio/base \
--namespace istio-system --create-namespace \
--version 1.27.1 --set defaultRevision=default
istiod-values.dev.yaml:
meshConfig:
enablePrometheusMerge: true
accessLogEncoding: JSON
accessLogFile: /dev/stdout
global:
defaultResources:
requests:
cpu: 50m
memory: 128Mi
hub: m.daocloud.io/docker.io/istio
imagePullPolicy: IfNotPresent
helm upgrade --install istiod istio/istiod \
--namespace istio-system --version 1.27.1 \
-f istiod-values.dev.yaml --wait
gateway-values.dev.yaml:
service:
type: NodePort
ports:
- name: status-port
port: 15020
protocol: TCP
targetPort: 15020
nodePort: 30520
- name: http2
port: 80
protocol: TCP
targetPort: 8080
nodePort: 30080
- name: https
port: 443
protocol: TCP
targetPort: 8443
nodePort: 30443
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: "2"
memory: 1Gi
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 5
targetCPUUtilizationPercentage: 80
imagePullPolicy: IfNotPresent
helm upgrade --install istio-ingress istio/gateway \
--namespace istio-system --version 1.27.1 \
-f gateway-values.dev.yaml --wait
Kiali、Jaeger、Prometheus、Grafana 等附加组件不随上述核心 Chart 一起安装;实验环境可使用 Istio release 包中的 samples/addons/ 清单,生产环境应按各组件自己的生命周期独立管理。
历史环境记录:Kubernetes 1.23 + Istio 1.13.1
以下内容用于复现实验室中的旧环境,不代表当前版本兼容性建议。版本选择应以当前 Istio Supported Releases 为准。
tar zxvf istio-1.13.1.tar.gz
cd istio-1.13.1
export PATH="$PWD/bin:$PATH"
install -m 0755 bin/istioctl /usr/local/bin/istioctl
# 离线环境在工作节点导入所需镜像
docker load -i pilot.tar.gz
docker load -i proxyv2.tar.gz
docker load -i httpbin.tar.gz
# demo profile 仅用于学习和功能验证
istioctl install --set profile=demo -y
kubectl get pods -n istio-system
# 卸载
istioctl x uninstall --purge -y
IstioOperator 配置:测试环境
对于istio安装,也是建议用istioctl工具安装,首先需要声明istioOperator的配置:
创建 istio-system Namespace
kubectl create ns istio-system
声明 IstioOperator 配置
创建istio-operator.yaml:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: example-istio
namespace: istio-system
spec:
hub: m.daocloud.io/docker.io/istio # 修改镜像地址
meshConfig:
accessLogEncoding: JSON
accessLogFile: /dev/stdout
# https://istio.io/latest/docs/setup/additional-setup/config-profiles/
profile: default # 生产环境建议直接用default就行。
components:
base:
enabled: true
cni:
enabled: false
egressGateways:
- enabled: false
name: istio-egressgateway
ingressGateways:
- enabled: true
name: istio-ingressgateway
k8s: # ingressgateway自己的pod端口配置
service: # 将Service类型改成NodePort
type: NodePort
ports:
- name: status-port
port: 15020
nodePort: 30520
- name: http2
port: 80 # 流量入口80端口映射到NodePort的30080,之后通过节点IP+30080即可访问Istio服务
nodePort: 30080
targetPort: 8080
- name: https
port: 443
nodePort: 30443
targetPort: 8443
安装 Istio
istioctl install -f istio-operator.yaml
# This will install the Istio 1.26.0 profile "default" into the cluster.
# Proceed? (y/N) y
Profile 选项
-
使用
istioctl安装 Istio 时,会根据指定的 profile 来选择使用的 Istio 配置文件。 -
profile 参数是一个预定义的配置选项,用于快速设置 Istio 的安装配置。每个 profile 都对应一个特定的 YAML 配置文件,其中包含了一组预定义的配置选项。
-
在 Istio 的安装过程中,profile 参数可以指定为以下一些值:
-
demo:用于演示和功能验证,启用较多能力和较高日志级别,不建议直接用于生产。 default:生产部署的常用起点,通常包含istiod和 ingress gateway。-
minimal:只安装控制平面istiod,适合使用独立网关或资源受限的场景。 -
istioctl install 本质上是根据选择的 profile 来加载对应的 YAML 配置文件,并将配置部署到 Kubernetes 集群中。
-
如果你想查看 demo 配置文件的内容,可以通过以下命令查找 Istio 的安装目录并找到对应的文件:
istioctl profile dump demo
这将打印出 demo 配置的完整内容,包括各个组件的配置选项。你也可以在 Istio 官方文档中找到各种预定义的 profile 配置选项的详细信息。
IstioOperator 配置:生产环境
测试环境安装出来的isitio和ingressgateway只有一个副本。生产环境建议两个以上的服务。
创建 istio-system Namespace
kubectl create ns istio-system
声明 IstioOperator 配置
生产环境至少为控制平面和入口网关配置多副本、HPA、资源请求与限制:
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
name: example-istio
namespace: istio-system
spec:
hub: m.daocloud.io/docker.io/istio
meshConfig:
accessLogEncoding: JSON
accessLogFile: /dev/stdout
components:
base:
enabled: true
cni:
enabled: false
egressGateways:
- enabled: false
name: istio-egressgateway
pilot: # istiod组件的hpa
k8s:
hpaSpec:
minReplicas: 2 # 默认为1
maxReplicas: 5 # 默认为5
resources:
limits: # 生产环境建议4C4G/4C8G
memory: 2Gi
cpu: "2"
requests: # 生产环境建议4C4G/4C8G(和limit一样,提高QoS)
memory: 128Mi
cpu: "100m"
ingressGateways:
- enabled: true
name: istio-ingressgateway
k8s: # ingressGateway的hpa配置
hpaSpec:
minReplicas: 2 # default 1
maxReplicas: 5 # default 5
resources:
limits: # 生产环境建议4C4G/4C8G
memory: 2Gi
cpu: "2"
requests: # 生产环境建议4C4G/4C8G(和limit一样,提高QoS)
memory: 128Mi
cpu: "100m"
service: # 将Service类型改成NodePort
type: NodePort
ports:
- port: 15020
nodePort: 30520
name: status-port
- port: 80 # 流量入口80端口映射到NodePort的30080,之后通过节点IP+30080即可访问Istio服务
nodePort: 30080
name: http2
targetPort: 8080
- port: 443
nodePort: 30443
name: https
targetPort: 8443
安装 Istio
istioctl install -f istio-operator.yaml
# This will install the Istio 1.26.0 profile "default" into the cluster.
# Proceed? (y/N) y
Sidecar 自动注入与退出
Istio 自动注入 Sidecar 的方式有两种:
- Namespace 级别:给 Namespace 添加
istio-injection=enabled标签;在该 Namespace 中新建或重建的 Pod 会被自动注入 Sidecar。 - Pod 级别:在 Pod template 的 annotations 中设置
sidecar.istio.io/inject: "true";设为"false"可覆盖 Namespace 的自动注入设置。
测试 Sidecar 注入
创建测试ns:
kubectl create ns istio-test
kubectl label namespace istio-test istio-injection=enabled
切换目录至 istio 的安装包解压目录,里面有自带的测试用pod。然后创建测试应用,此时创建的 Pod 会被自动注入一个 istio proxy 的容器(因为这个pod创建在了开启sidecar注入的ns下面):
cd istio-1.27.0/sample/sleep/
# 更改测试服务的镜像地址:
vim sleep.yaml
image: m.daocloud.io/docker.io/curlimages/curl
# 创建测试服务:
kubectl apply -f sleep.yaml -n istio-test
如果需要给Pod单独添加istio-proxy,可以给Pod添加sidecar.istio.io/inject=true标签即可:
template:
metadata:
labels:
app: sleep
annotations:
sidecar.istio.io/inject: "true"
关闭 Sidecar 注入
如果某个服务不想被注入sidecar,可以添加sidecar.istio.io/inject=false的标签即可:
cd istio-1.27.0/samples/curl
vim curl.yaml
template:
metadata:
labels:
app: curl
annotations:
sidecar.istio.io/inject: "false"
spec:
terminationGracePeriodSeconds: 0
serviceAccountName: curl
containers:
- name: curl
image: m.daocloud.io/docker.io/curlimages/curl
如果想要关闭该Namespace的自动注入,直接去除标签即可(已注入的Pod不受影响,下次重建后,不再有isito-proxy的容器)
kubectl label namespace istio-test istio-injection-
最常用的的方式
- 打开某个ns的istio sidecar注入,其中个别pod不需要sidecar,就打标签关闭注入。
- 单独开某几个pod的情况比较少
可观测性组件
Kiali
Kiali为Istio提供了可视化的界面,可以在Kiali上进行观测流量的走向、调用链,同时还可以使用Kiali进行配置管理。
安装 Kiali
kiali就在istio的安装包中,service改成NodePort,直接安装即可
在 samples/addons/kiali.yaml 中将 Kiali Service 调整为 NodePort:
apiVersion: v1
kind: Service
metadata:
name: kiali
namespace: "istio-system"
spec:
type: NodePort
kubectl apply -f ./istio-1.27/samples/addons/kiali.yaml
# 通过NodePort高位端口访问UI界面
Jaeger 链路追踪
除了Kiali 之外,还可以安装一个链路追踪的工具,安装该工具可以在Kiali的Workloads页面,查看某个服务的Traces信息:
cd ./istio-1.27.0/samples/addons
# 首先更改镜像地址
vim samples/addons/jaeger.yaml
# 更改名称为tracing的svc为NodePort
vim samples/addons/jaeger.yaml
需要修改的关键配置:
# Deployment/Pod template 中的镜像
image: "m.daocloud.io/docker.io/jaegertracing/all-in-one:1.67.0"
---
apiVersion: v1
kind: Service
metadata:
name: tracing
namespace: istio-system
labels:
app: jaeger
spec:
type: NodePort
ports:
- name: http-query
port: 80
protocol: TCP
targetPort: 16686
# Note: Change port name if you add '--query.grpc.tls.enabled=true'
- name: grpc-query
port: 16685
protocol: TCP
targetPort: 16685
selector:
app: jaeger
# 创建
kubectl create -f samples/addons/jaeger.yaml
# 通过NodePort高位端口访问UI界面
注意:公司如果真需要上链路追踪,建议用更专业的Skywalking。jaeger这个比较简单而且也不太好用。
Prometheus 与 Grafana
Istio 默认暴露了很多监控指标,比如请求数量统计、请求持续时间以及Service和工作负载的指标,这些指标可以使用Prometheus进行收集,Grafana进行展示。
Istio 内置了Prometheus和Grafana的安装文件,直接安装即可。
也可以使用外置的Prometheus和Grafana。
但是建议istio的prometheus和grafana单独安装,因为集群自己的prometheus需要监控很多集群其他指标,不建议再接入istio的指标。istio用自己独立的prometheus和grafana即可。
安装
# 同样需要修改镜像地址
vim samples/addons/grafana.yaml
image: "m.daocloud.io/docker.io/grafana/grafana:11.3.1"
vim samples/addons/prometheus.yaml
image: "m.daocloud.io/docker.io/prom/prometheus:v3.2.1"
# 修改svc为NodePort
vim samples/addons/grafana.yaml # 修改name为grafana的svc
vim samples/addons/prometheus.yaml # 修改名为prometheus的svc
# 安装
kubectl create -f samples/addons/prometheus.yaml -f samples/addons/grafana.yaml
# 完成后通过NodePort高位端口访问grafana
Grafana Dashboard
进入到Grafana dashboard可以看到默认已经加进去了istio相关的dashboard。
进入Istio Control Plane Dashboard:
- 有一个指标叫:“Push Erros”,代表当前的配置分发到数据平面有没有报错。可以着重看这个指标
进入Istio Mesh Dashboard:
- 这是全局监控面板,如果出现性能问题,可以在其中查看相关指标。
进入Istio Performance Dashboard:
- 这里面显示了istio的资源使用情况。出现性能问题同样可以在其中查看。
进入Istio Service Dashboard和Istio Workload Dashboard:
- 可以看到服务间访问的链路情况。
Bookinfo 流量治理实践
istio官网提供了BookInfo项目:Istio Bookinfo Application
部署 Bookinfo 项目
创建ns并添加自动注入标签:
kubectl create ns bookinfo
kubectl label ns bookinfo istio-injection=enabled
修改项目里面的镜像地址:
vim samples/bookinfo/platform/kube/bookinfo.yaml
image: m.daocloud.io/docker.io/istio/examples-bookinfo-details-v1:1.20.3
image: m.daocloud.io/docker.io/istio/examples-bookinfo-ratings-v1:1.20.3
image: m.daocloud.io/docker.io/istio/examples-bookinfo-reviews-v1:1.20.3
image: m.daocloud.io/docker.io/istio/examples-bookinfo-reviews-v2:1.20.3
image: m.daocloud.io/docker.io/istio/examples-bookinfo-reviews-v3:1.20.3
image: m.daocloud.io/docker.io/istio/examples-bookinfo-productpage-v1:1.20.3
部署服务:
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml -n bookinfo
使用域名发布服务
接下来创建Istio的Gateway和VirtualService实现域名访问Bookinfo项目。
创建 Gateway
首先创建Gateway,假设发布的域名是bookinfo.kubeasy.com。Gateway配置如下所示:
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: bookinfo-gateway
namespace: bookinfo
spec:
# The selector matches the ingress gateway pod labels.
# If you installed Istio using Helm following the standard documentation, this would be "istio=ingress"
selector:
istio: ingressgateway # 使用默认的istio ingress gateway
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "bookinfo.kubeasy.com" # 发布域名
创建 VirtualService
接下来创建VirtualService,实现对不同微服务的访问
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo
namespace: bookinfo
spec:
hosts:
- "bookinfo.kubeasy.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
部署Gateway和VS:
kubectl apply -f bookinfo-gateway.yaml -f bookinfo-vs.yaml -n bookinfo
发布域名
接下来,在宿主机上将域名bookinfo.kubeasy.com解析至集群任意一个安装了kube-proxy的节点IP上。通过ingressgateway的Service的NodePort即可访问到Bookinfo:
kubectl get svc -n istio-system istio-ingressgateway
- 绑定hosts后,通过bookinfo.kubeasy.com +【ingressgateway 80 端口对应的NodePort(30080)】即可访问该服务。注意加上接口路径。比如本次示例:
bookinfo.kubeasy.com:30080/productpage
(实际生产环境中有前端LB,外部用户要访问的话需要把域名解析到前端LB的IP,默认是80/443端口,就不用写端口号了。由LB再把请求转发到后端ingressgateway上面)
-
多访问几次,可以看到Reviewer处的星星会在黑色、红色和消失之间来回替换,是因为部署了三个不同版本的reviews,每个版本具有不同的显示效果。
-
然后去kiali - traffic graph里面看到流量链路图。
地址重写和重定向
Istio 同样支持访问地址的重写和重定向,这个功能一般用于新旧域名的替换和移动端、桌面端互相跳转。效果是访问某个域名的某个路径时,自动跳转到另一个域名的另一个路径。
详细配置文档:Istio HTTPRedirect
域名重定向
比如将bookinfo.kubeasy.com/hangx跳转到edu.51cto.com/lecturer/11062970.html,在VS里面配置:
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.kubeasy.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
prefix: /hangx # 匹配/hangx
redirect:
authority: edu.51cto.com # 跳转的域名
uri: /lecturer/11062970.html # 跳转的路径
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
kubectl apply -f bookinfo-vs.yaml -n bookinfo
地址重写
地址重写的一个典型应用场景就是:
- 同一个域名代理多个后端服务,例如
test.com对应 a、b、c 三个服务,需要通过/a、/b、/c路由到不同后端。 - 但是对于a、b、c服务的三个后端pod,开发出来对外暴露的接口都是/api。你直接访问test.com/a报404,因为pod根本没暴露这个接口,人家暴露的是/api
- 这就需要根据域名/路径,重定向到后端服务。比如将test.com/a重写为test.com/api,route配置为a服务的svc。
我们上面bookinfo项目默认根路径是报错404的:bookinfo.kubeasy.com:30080/,我们可以配置根路径访问到/productpage页面。在VS中配置:
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: bookinfo
spec:
hosts:
- "bookinfo.kubeasy.com"
gateways:
- bookinfo-gateway
http:
- match:
- uri:
exact: / # 匹配根路径
rewrite: # 地址重写为/productpage
uri: /productpage
route: # 指定rewrite到哪个
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
- match:
- uri:
exact: /productpage
- uri:
prefix: /static
- uri:
exact: /login
- uri:
exact: /logout
- uri:
prefix: /api/v1/products
route:
- destination:
host: productpage.bookinfo.svc.cluster.local
port:
number: 9080
kubectl apply -f bookinfo-vs.yaml -n bookinfo
灰度发布
使用Istio进行细粒度的流量管理,步骤如下:
- 创建DR划分subset
- 创建VS将100%流量导向旧版本
- 部署新版本
- 使用VS逐渐切换比例流量到新版本
创建 DestinationRule 划分子集
在bookinfo项目中,有三个版本的reviews服务(svc只有一个,pod有三个版本的共存;每组的pod都打好了标签version=v1、v2、v3)。
首先通过DestinationRule将reviews分成三个版本:
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews
spec:
host: reviews.bookinfo.svc.cluster.local
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
kubectl apply -f bookinfo-canary-dr.yaml -n bookinfo
创建 VirtualService 路由流量
- 首先将所有流量路由到v1:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.bookinfo.svc.cluster.local
http:
- route:
- destination:
host: reviews.bookinfo.svc.cluster.local
subset: v1 # 将流量全部指向v1
kubectl apply -f vs-reviews-canary.yaml -n bookinfo
- 开发了v2版本上线,现在把20%流量切到v2作为灰度发布:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.bookinfo.svc.cluster.local
http:
- route:
- weight: 80
destination:
host: reviews.bookinfo.svc.cluster.local
subset: v1
- weight: 20
destination:
host: reviews.bookinfo.svc.cluster.local
subset: v2
kubectl apply -f vs-reviews-v2-all.yaml -n bookinfo
- 将流量全部导向v2
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.bookinfo.svc.cluster.local
http:
- route:
- destination:
host: reviews.bookinfo.svc.cluster.local
subset: v2
kubectl apply -f vs-reviews-v1-all.yaml -n bookinfo
A/B 测试
Istio也支持基于请求头、uri、schema等方式的细粒度流量管理,这种路由方式比较适用于新版本上线时的AB测试。
Istio请求头匹配介绍:Istio HTTPMatchRequest
假如bookinfo项目又开发了一个新版v3,此时只想要公司内部的测试组先进行测试,可以配置VirtualService指定部分用户访问新版本。
- 再次修改reviews的VirtualService,将jason用户指向v3,其他用户依旧使用v2版本:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: reviews
spec:
hosts:
- reviews.bookinfo.svc.cluster.local
http:
- match:
- headers: # 匹配请求头
end-user: # 匹配请求头的key为end-user。根据实际情况填写合适的header头
exact: jason # value 为jason,也支持prefix、regex
route:
- destination:
host: reviews.bookinfo.svc.cluster.local
subset: v3 # 匹配到end-user=jason路由至v3版本
- route:
- destination:
host: reviews.bookinfo.svc.cluster.local
subset: v2 # 其余用户路由到v2版本
kubectl apply -f vs-ab-json-v3.yaml -n bookinfo
在bookinfo.kubeasy.com:30080/productpage页面上登录,user为jason,密码随便写。登录后可以发现使用的是v3版本的reviews(星星颜色为红色)
- 当AB测试完成后,可以再接上一个灰度发布,20%到v3,80%到v2。
- 灰度发布完成后,再完全切换流量到v3
负载均衡算法
k8s原生可以调整节点级别kube-proxy ipvs的负载均衡算法,但是不支持精细化到pod级别的负载均衡算法,Istio可以。
Istio原生支持多种负载均衡算法,比如ROUND_ROBIN、LEAST_REQUEST、LEAST_CONN、RANDOM等。假如一个应用存在多个副本(Pod),可以使用上述算法对多个Pod进行定制化的负载均衡配置。
常见的负载均衡策略如下:
- ROUND_ROBIN:轮询算法,将请求依次分配给每一个实例,不推荐使用。
[!warning] 只要涉及到负载均衡算法,都不推荐使用轮询,已经被证实存在很多问题,比如:某个节点由于性能问题(比如cpu、内存高),导致上面pod处理请求比较慢,但是轮询是感知不到的。会导致请求不断还是会继续发送到这个节点的pod上,导致这个pod一直cpu飚高,但是其他pod空闲。
-
LEAST_REQUEST:最小链接算法,从池中随机选择两个实例pod,并将请求路由给当前活跃请求数较少的那个主机。
【生产环境建议】 -
RANDOM:随机算法,将请求随机分配给其中一个实例。
-
PASSTHROUGH:将连接转发到调用者请求的原始 IP 地址,而不进行任何形式的负载均衡,目前不推荐使用。
-
UNSPECIFIED:未指定负载均衡算法,Istio将选择一个合适的默认算法,不推荐使用。
更改负载均衡算法
更改负载均衡算法需要在DR上配置,因为DR才是控制流量作用到pod上的。
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: reviews
spec:
trafficPolicy: # 添加路由策略,在spec下对所有的subset生效,也可以在subset中配置
loadBalancer: # 配置负载均衡
simple: RANDOM # 策略为RANDOM
host: reviews.bookinfo.svc.cluster.local
subsets:
- name: v1
labels:
version: v1 # subset v1指向具有version=v1的Pod
trafficPolicy: # 对于v1的所有pod配置单独的负载均衡算法
loadBalancer: # 配置负载均衡
simple: LEAST_REQUEST # 策略为RANDOM
- name: v2
labels:
version: v2 # subset v2指向具有version=v2的Pod
- name: v3
labels:
version: v3 # subset v3指向具有version=v3的Pod
kubectl apply -f bookinfo-canary-dr.yaml -n bookinfo
熔断与连接池
Istio支持熔断机制,可以实现在高并发时对服务进行过载保护。比如部署了一个大模型服务,只能同时支持100用户请求。此时来了高于100个请求,就会造成服务宕机,影响前100个正常用户的访问。这样影响太大。可以设置熔断,超过最大并发量的时候,新进来的请求返回一个“当前繁忙,请稍后再试”之类的友好提示。
假设对ratings进行熔断,希望在并发请求数超过3,并且存在1个以上的待处理请求,就触发熔断。因为熔断也是在最终实例pod上生效的,也是在DR上配置的。
DestinationRule 配置熔断
此时可以配置ratings的DestinationRule如下所示:
# vim ratings-dr.yaml
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: ratings
namespace: bookinfo
spec:
host: ratings.bookinfo.svc.cluster.local
trafficPolicy: # trafficPolicy配置,也可以配置在subsets级别
connectionPool: # 连接池配置,可以单独使用限制程序的并发数
tcp:
maxConnections: 3 # 最大并发数为3
http:
http1MaxPendingRequests: 1 # 最大的待处理请求。
# 假如有2个待处理请求,就触发了熔断,不让你排队了,因为排队也没有用了
outlierDetection: # 熔断探测配置
consecutive5xxErrors: 1 # 如果连续出现的5xx错误超过1次,就会被熔断
interval: 10s # 每10秒探测一次后端实例
baseEjectionTime: 3m # 熔断的时间。某个后端pod触发熔断后,也不能一直不接受请求。3分钟之后,估算着请求应该都处理完成了,重新接受请求。
maxEjectionPercent: 100 # 被熔断实例最大的百分比。比如10个pod,10个都能触发熔断就是100。测试用写100。实际写50就可以,太高会造成其他实例出现性能问题。
subsets:
- name: v1
labels:
version: v1
Fortio 压测
istio安装包提供了压测工具fortio,先部署一下:
# 修改镜像
vim samples/httpbin/sample-client/fortio-deploy.yaml
# 部署
kubectl apply -f samples/httpbin/sample-client/fortio-deploy.yaml -n bookinfo
获取容器ID并发送请求:
FORTIO_POD=$(kubectl get pod -n bookinfo | grep fortio | awk '{ print $1 }')
echo $FORTIO_POD
kubectl exec -ti $FORTIO_POD -n bookinfo -- fortio load -curl http://ratings:9080/ratings/0
接下来更改为两个并发连接(-c 2),发送20请求(-n 20):
kubectl exec -ti $FORTIO_POD -n bookinfo -- fortio load -c 2 -qps 0 -n 20 -loglevel Warning http://ratings:9080/ratings/0 | grep Code
可以看到请求都是成功的,说明pod处理这些请求速度很快,请求没有排队待处理
提高并发量,会触发熔断:
kubectl exec -ti $FORTIO_POD -n bookinfo -- fortio load -c 20 -qps 0 -n 20 -loglevel Warning http://ratings:9080/ratings/0 | grep Code
Code 200 : 5 (25.0 %)
Code 503 : 15 (75.0 %)
说明触发了熔断,pod没有直接挂掉,实现了过载保护。
参数含义与调优方法
maxConnections:到单个目标实例的 TCP 最大连接数,应结合应用并发能力、连接复用方式和 Pod 资源上限压测确定。http1MaxPendingRequests:HTTP/1.1 最大挂起请求数,超过阈值的新请求会被拒绝,用于阻止队列无限增长。maxRequestsPerConnection:单连接最多处理的请求数,可限制过长连接,但过小会增加建连成本。consecutive5xxErrors/consecutiveGatewayErrors:触发实例驱逐前允许的连续错误数。interval:异常实例检测周期;baseEjectionTime:基础驱逐时长;maxEjectionPercent:最多可同时驱逐的实例比例。
参数没有通用最优值。应从应用真实的并发上限、P99、错误率、连接模型和副本数出发,在测试环境逐步增加压力;生产配置还要避免 maxEjectionPercent 过高导致剩余实例过载。
故障注入
延迟
主要用来测试链路可靠性,比如三个服务A-B-C,由于偶发网络延迟高,C服务响应变慢,是否会影响A、B服务?这是链路可靠性的问题,需要我们进行测试。
首先创建测试工具,测试访问details服务的时间:
kubectl create deploy -n bookinfo debug-tools --image=registry.cn-beijing.aliyuncs.com/dotbalo/debug-tools -- sleep 36000
kubectl exec -ti debug-tools-5887bf6774-598tc -n bookinfo -- bash
time curl -I -s details:9080
不添加任何故障延迟时,0.02秒左右就会返回结果。接下来注入一个5s的延迟。由于故障注入属于service级别,所以是在vs上配置:
# vim details-delay.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: details
spec:
hosts:
- details.bookinfo.svc.cluster.local
http:
- fault: # 添加一个错误
delay: # 添加类型为delay的故障
percentage: # 故障注入的百分比
value: 100 # 对所有请求注入故障
fixedDelay: 5s # 注入的延迟时间
route:
- destination:
host: details
kubectl create -f details-delay.yaml -n bookinfo
再返回测试工具进行测试,响应时间变成了5s:
time curl -I -s details:9080
假设我们有A服务去访问details服务,设置的超时时间为2s,这样通过延迟故障注入,我们可以测试这个超时时间配置是否生效。
中断
注入中断故障,可以模拟服务返回指定的状态码(400、503等),上游服务的处理是否符合预期。(上游服务如果接收到异常状态码,也抛出异常,那就不正确了;需要配置上异常处理才算是合理的代码)
中断故障注入只需要将fault 的delay更改为abort即可:
# vim details-abort.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: details
spec:
hosts:
- details
http:
- fault:
abort: # 更改为abort类型的故障
percentage:
value: 100
httpStatus: 400 # 故障状态码
route:
- destination:
host: details
超时实践:Nginx 调用 Tomcat
生产环境中,上游等待下游响应过久会积压请求,最终可能造成级联故障。这个实验让客户端访问 Nginx,Nginx 再代理 Tomcat:Tomcat 被注入 10 秒延迟,而客户端到 Nginx 的路由超时为 2 秒,因此客户端会在约 2 秒后收到超时响应。
先部署两个服务;实验 Namespace 需要启用 Sidecar 注入:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14-alpine
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- name: http
port: 80
targetPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: tomcat
spec:
replicas: 1
selector:
matchLabels:
app: tomcat
template:
metadata:
labels:
app: tomcat
spec:
containers:
- name: tomcat
image: docker.io/kubeguide/tomcat-app:v1
---
apiVersion: v1
kind: Service
metadata:
name: tomcat-svc
spec:
selector:
app: tomcat
ports:
- name: http
port: 8080
targetPort: 8080
将 Nginx 的 / 代理到 http://tomcat-svc.default.svc.cluster.local:8080,然后应用下面的路由策略:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: nginx-timeout
spec:
hosts:
- nginx-svc
http:
- timeout: 2s
route:
- destination:
host: nginx-svc
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: tomcat-delay
spec:
hosts:
- tomcat-svc
http:
- fault:
delay:
fixedDelay: 10s
percentage:
value: 100
route:
- destination:
host: tomcat-svc
验证:
kubectl run busybox --image=busybox:1.28 --restart=Never --rm -it -- /bin/sh
# Tomcat 约 10 秒返回
time wget -q -O - http://tomcat-svc.default.svc.cluster.local:8080
# Nginx 路由约 2 秒超时
time wget -q -O - http://nginx-svc.default.svc.cluster.local:80
重试实践与边界
重试用于处理短暂网络故障或瞬时 5xx,但只应对幂等请求启用,并设置单次超时和总超时预算,避免重试放大下游压力。策略应绑定到调用方实际访问的目标主机;Nginx 访问 Tomcat 时,hosts 应是 tomcat-svc:
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: tomcat-retry
spec:
hosts:
- tomcat-svc
http:
- timeout: 8s
retries:
attempts: 3
perTryTimeout: 2s
retryOn: 5xx,connect-failure,reset
route:
- destination:
host: tomcat-svc
attempts: 3 表示初始请求失败后最多重试 3 次,perTryTimeout 限制每次尝试,timeout 限制整次请求的总预算。可通过调用方 Pod 的 istio-proxy 日志验证重试行为:
kubectl logs -f deploy/nginx -c istio-proxy
故障注入与重试测试要分开
Istio 的 HTTP 故障注入用于模拟异常路径,不应直接当作验证重试次数的后端故障源。验证重试时,应让测试服务真实返回可重试状态码或主动断开连接,然后结合代理日志和请求计数确认实际尝试次数。
运维检查清单
- 安装前核对 Kubernetes 与 Istio 的版本兼容矩阵,并明确使用 Sidecar、Ambient 还是混合模式。
- 生产环境为
istiod和 ingress gateway 配置多副本、反亲和、PDB、HPA 与合理的资源请求。 - 修改 VirtualService、DestinationRule、Gateway 后,用
istioctl analyze检查配置,再观察控制平面 Push Errors、5xx 与 P99。 - 灰度、重试、熔断和故障注入均先在测试环境压测;确保有明确的回滚步骤和流量恢复路径。
- 删除 Namespace 注入标签不会移除已有 Sidecar;需要滚动重建工作负载才能生效。