本文基于 Istio 1.31.3(2026-10)官方文档重写,重点讲清原理,再落到安装、流量、安全、可观测性和企业实践。旧笔记写于 Istio 1.9,只覆盖了 Service Mesh 概念和少量组件;1.31 的变化较大:Mixer 早已移除,控制面统一为 istiod,配置 API 以 v1 为主,数据面除了 Envoy Sidecar 还有 Ambient 模式(ztunnel + waypoint),入口治理推荐 Gateway API。
1.31.0 于 2026-08-31 发布,官方支持 Kubernetes 1.32–1.36。1.31 值得注意的变化包括:Ambient 的 Address 变更只推送给受影响的 waypoint(AMBIENT_SCOPED_ADDRESS_PUSHES)、waypoint 加权金丝雀、ServiceEntry 可见性控制、AuthorizationPolicy 支持按信任域匹配、FIPS 140-3 合规策略,以及默认发送不健康 Endpoint 的行为变化。
最后更新:2026-10-23
版本与范围
- 版本基线:Istio 1.31.3;Kubernetes 1.32–1.36
- 配置 API:
networking.istio.io/v1、security.istio.io/v1、telemetry.istio.io/v1 - 数据面:Sidecar 与 Ambient 两种模式,可在同一网格中共存
- 本文重点:架构原理、流量与安全的实现机制、可观测性,以及企业落地时的升级、隔离、容量和排障
阅读前需要了解 Kubernetes 的 Pod、Service、Deployment、Ingress、CRD 和 NetworkPolicy。
Service Mesh 与 Istio
服务网格是处理服务间通信的基础设施层,把服务发现、负载均衡、重试、熔断、mTLS、遥测和访问控制从应用代码里下沉到代理层。
它解决的核心问题是:微服务之间的通信逻辑散落在各个语言、各个框架里,协议不一致、可观测性不统一、安全策略难以统一落地。把这些能力抽到代理层之后,应用只负责业务,通信治理由基础设施统一完成。
Istio 提供的能力:
- 流量管理:路由、灰度、重试、超时、熔断、故障注入、流量镜像
- 安全:工作负载身份、自动 mTLS、JWT 认证、细粒度授权
- 可观测性:统一指标、访问日志、分布式追踪
- 策略与扩展:限流、Wasm 插件、外部授权
Istio 不负责的事情:
- 不能替代应用自身的幂等、事务和业务降级
- 不是万能的网络安全边界,绕过 Sidecar 的流量仍可能存在
meshConfig.outboundTrafficPolicy.mode: REGISTRY_ONLY只能减少意外外联,不能当作强安全策略
核心架构
Istio 逻辑上分为控制面和数据面:控制面负责“告诉代理怎么转发”,数据面负责“真正转发流量”。
图 1:Istio 官方架构图(Sidecar 模式):控制面 istiod + 数据面 Envoy
控制面 istiod
istiod 由早期的 Pilot、Citadel、Galley 合并而来,负责:
- 服务发现:把 Kubernetes Service、Endpoint、ServiceEntry 等转换为标准模型
- 配置分发:把 VirtualService、DestinationRule、Gateway 等转换为 Envoy 配置,通过 xDS 下发
- 证书管理:作为 CA 为工作负载签发 X.509 证书,支持证书轮换
- 配置校验与状态汇总
istiod 常用端口:
| 端口 | 用途 |
|---|---|
| 15010 | xDS/CA,明文,仅限可信网络 |
| 15012 | xDS/CA,TLS/mTLS,生产推荐 |
| 15014 | 控制面监控指标,HTTP |
| 15017 | Webhook 容器端口,由 Service 443 转发,承载注入与校验 |
生产环境至少运行 2 个 istiod 副本。注入 Webhook 的 failurePolicy: Fail 时,单个 istiod 副本会成为集群创建 Pod 的单点:副本不可用时,所有新建 Pod 都会被拒绝。
控制面内部:从对象到 xDS 的编译流水线
istiod 不是一个“转发配置的 Kafka”,而是一个持续运行的编译器:
Kubernetes API / ServiceEntry / CRD |
几个关键点:
- Push Context 是快照:一次推送基于当时的服务和配置状态生成,避免边生成边读到不一致的数据。
- Debounce 合并变更:短时间大量 Endpoint/Pod 变化会被合并,避免每个事件都触发全量重算。
- 按代理裁剪:每个代理只应看到自己需要的 Listener/Route/Cluster/Endpoint;
Sidecar、exportTo、discoverySelectors都在这个阶段生效。 - ACK/NACK:代理应用成功后回 ACK;配置非法时回 NACK,并继续使用上一份可用配置。控制面会记录 NACK 并重试,但不会“强制”代理接受坏配置。
- 多副本不是分片:每个 istiod 副本都能服务任意代理;副本之间通过 leader election 协调部分控制器,代理连接由 Service 负载均衡。扩容副本主要提升推送并发和可用性,不自动分摊单个超大网格的配置生成成本。
xDS 协议细节:version、nonce 与一致性
ADS 把 CDS/EDS/LDS/RDS/SDS 聚合到一条 gRPC 流上,避免多条流之间的顺序错乱。一次响应的关键字段:
| 字段 | 作用 |
|---|---|
version_info |
资源版本;代理 ACK 时带回,控制面据此判断是否同步 |
nonce |
本次响应的唯一标识;ACK/NACK 必须带回对应 nonce |
resource_names |
代理订阅的资源名(如 cluster 名称) |
error_detail |
NACK 时由代理返回,说明拒绝原因 |
istioctl proxy-status 的 SYNCED / STALE / NOT SENT 就是这条状态机的可视化:
SYNCED:代理已 ACK 最新版本。STALE:控制面已发送更新,但代理尚未 ACK(可能正在应用、网络慢、或 NACK)。NOT SENT:控制面还没有向该代理发送配置(常见于刚启动或订阅范围为空)。
配置“看起来 apply 了但没生效”,通常不是 istiod 没收到,而是:代理 NACK、配置作用域没覆盖到、Endpoint 尚未就绪、或应用复用了旧连接。
控制面排障入口
istioctl proxy-status:看每个代理的同步状态和最近一次 NACK。istioctl proxy-config cluster/route/listener/endpoint/secret <pod>:看代理实际持有的配置,而不是看 CRD 推测。istioctl analyze -A:静态检查配置引用、Gateway 绑定、mTLS 冲突等。- istiod
15014/debug/syncz、/debug/config_dump、/debug/registryz:控制面视角的同步与注册表状态;默认启用调试端点认证(ENABLE_DEBUG_ENDPOINT_AUTH),不要裸露到不可信网络。 15010是明文 xDS/CA,15012是 TLS/mTLS;生产应优先使用15012,并限制15010的访问。
配置如何生效:xDS 原理
Envoy 的配置可以抽象成一条链:
Listener → Filter Chain → Route → Cluster → Endpoint |
对应到 xDS:
- LDS(Listener Discovery Service):监听器,决定在哪个端口、用什么协议接收流量
- RDS(Route Discovery Service):路由,决定请求匹配到哪个 cluster
- CDS(Cluster Discovery Service):集群,表示一组上游服务
- EDS(Endpoint Discovery Service):端点,表示上游的具体 Pod IP 和端口
- SDS(Secret Discovery Service):证书和密钥。Envoy 通过 SDS 向同 Pod 的 istio-agent 请求证书,istio-agent 再带 ServiceAccount 凭证向 istiod 发 CSR;istiod 不直接向 Envoy 推送 SDS
以 echo.default.svc.cluster.local:80 为例,istiod 生成的资源大致是:
LDS: 0.0.0.0:15001(出站)/ 0.0.0.0:15006(入站) |
这也是为什么排障要看代理视角,而不是只看 CRD:
istioctl proxy-config listener <pod> -n <ns> |
一次配置变更的过程:
kubectl apply修改 CRD- istiod watch 到变更,做基本校验和去重
- istiod 根据服务发现和 CRD 生成 Envoy 配置
- 通过 xDS 增量或全量推送给相关代理
- Envoy 应用配置并返回 ACK;配置非法时返回 NACK
istioctl proxy-status 的状态:
SYNCED:Envoy 已 ACK 最新配置STALE:istiod 已发送更新,但尚未收到 ACKNOT SENT:istiod 还没有给该代理发送配置
NACK 是 Envoy 拒绝 xDS 配置的响应,不是 proxy-status 的状态值;出现时通常表现为 STALE,需要看 istiod 日志、istioctl analyze 和 Envoy config dump。
因为配置是推送模型,变更通常几秒内生效;但大规模集群里,xDS 推送和 Envoy 应用都需要时间,不能假设“apply 完立即全量生效”。
推送风暴、作用域与 1.31 的优化
xDS 的成本不在“配置有多大”,而在“有多少代理 × 变更多频繁 × 每个代理要重算多少”:
- 变更频率:HPA 抖动、批量 Job、滚动发布都会持续改变 Endpoint。
- 扇出:一次 Service/Endpoint 变更可能影响大量代理。
- 配置规模:每个代理持有的 Listener/Cluster/Route 数量决定内存和生成时间。
控制手段:
| 手段 | 作用 | 注意 |
|---|---|---|
Sidecar 资源 |
限制命名空间/工作负载订阅的 host | 只裁剪配置,不阻断流量 |
exportTo |
控制 Service/Route 对哪些命名空间可见 | 跨命名空间调用可能变成无配置 |
discoverySelectors |
istiod 只发现匹配的命名空间 | 影响服务发现,不是网络隔离 |
serviceEntryVisibility(1.31) |
控制 ServiceEntry 的可见性 |
Ambient 默认强制执行;Sidecar 需 applyToSidecars |
AMBIENT_SCOPED_ADDRESS_PUSHES(1.31) |
Address 变更只推给受影响的 waypoint | 默认开启,可关闭用于回退 |
| 配置拆分 | 避免超大 VirtualService/AuthorizationPolicy | 降低单次生成和评审成本 |
1.31 还调整了 Ambient 的 WDS 重连行为:ztunnel 重连时会上报它持有的所有 workload 名称和版本,约 4 万个 workload 就可能超过 istiod 默认 4MiB 的 gRPC 接收上限,表现为 ResourceExhausted 重连循环。接近这个规模时,需要调大 ISTIO_GPRC_MAXRECVMSGSIZE(按官方升级说明,约每 1 万 workload/service 预留 1MiB)。
Sidecar 数据面原理
Sidecar 模式在每个业务 Pod 中注入一个 Envoy 容器。关键点是:业务容器和 Envoy 共享同一个网络命名空间,因此它们共享 localhost、网卡和端口空间。
流量拦截流程:
- Pod 创建时,注入 Webhook 在 Pod 中加入 Envoy 容器
istio-init初始化容器(或 istio-cni 节点代理)写入 iptables 规则- 出站流量被重定向到 Envoy 的 15001 端口
- 入站流量被重定向到 Envoy 的 15006 端口
- Envoy 通过
SO_ORIGINAL_DST还原原始目标地址,再按 xDS 配置转发
几个容易忽略的细节:
- 代理自身的流量通过 UID 1337 排除,避免无限回环
- 15020、15021、15090 等代理端口有单独的放行规则
- 应用仍然监听自己的端口,感知不到 Envoy 的存在
- 不能用
localhost访问“另一个容器”的端口,除非它们共享网络命名空间 - Sidecar 启动晚于应用时,应用启动期请求可能失败,可以开启
holdApplicationUntilProxyStarts
数据面端口:
| 端口 | 用途 |
|---|---|
| 15000 | Envoy admin,Pod 内可访问 |
| 15001 | 出站流量 |
| 15006 | 入站流量 |
| 15008 | HBONE mTLS 隧道(与 Ambient/HBONE 目的地通信) |
| 15020 | 合并指标 |
| 15021 | 健康检查 |
| 15053 | DNS 捕获 |
| 15090 | Envoy Prometheus 遥测 |
Sidecar 的优点是功能完整、成熟;缺点是每个 Pod 都有代理,资源开销和升级成本随 Pod 数量线性增长。
注入、CNI 与启动竞态
自动注入发生在 Pod 创建时,不是 Deployment 创建时。admission webhook 修改 Pod spec,加入 istio-proxy 容器和初始化逻辑;已经运行的 Pod 不会因为给命名空间打标签而自动获得 Sidecar,必须重建。
两种流量重定向方式:
- istio-init:初始化容器在 Pod 网络命名空间写 iptables 规则,需要
NET_ADMIN,通常配合限制性 SCC/PSP。 - istio-cni:节点级 CNI 插件,在 Pod 沙箱创建后配置重定向,不需要应用 Pod 持有
NET_ADMIN,生产更常用。
CNI 模式有一个经典竞态:节点刚变为可调度、CNI DaemonSet 还没就绪时,新 Pod 可能启动并绕过重定向。Istio 通过注入 istio-validation init container 检测重定向是否生效,并阻塞问题 Pod;CNI 的 repair 控制器会处理这些卡住的 Pod。该机制默认开启(values.cni.repair.enabled),不要为了“让 Pod 先起来”随意关闭。
CNI 与控制的版本兼容性:CNI 1.x 可与控制面 1.x-1、1.x、1.x+1 配合,升级顺序相对宽松,但仍应以官方兼容矩阵为准。
其他容易踩的点:
hostNetwork: true的 Pod 不走常规 Sidecar 拦截,需要单独评估。- 应用启动早于 Envoy 就绪时,启动期请求可能失败;可以开启
holdApplicationUntilProxyStarts,用启动延迟换取确定性。 - 明确排除不需要代理的端口(如某些监控/探针端口),但不要把业务端口排除,否则等于绕过 mTLS 和策略。
- 排障时先确认“流量有没有进代理”,再查路由和策略;
proxy-config listener能看到实际监听与 filter chain。
Ambient 数据面原理

图 2:Ambient 官方 L4 路径:源 ztunnel 通过 HBONE 到目标 ztunnel

图 3:Ambient 官方 L7 路径:源 ztunnel 把流量送到 waypoint,再转发到目标
Ambient 模式把数据面拆成两层:
- ztunnel:每个节点一个,Rust 编写,处理 L3/L4 的 mTLS、认证、L4 授权和遥测。ztunnel 不解析 HTTP,使用 HBONE(HTTP CONNECT 隧道)在节点间传输流量
- waypoint:按命名空间、Service 或 Pod 部署的 Envoy,提供 L7 路由、L7 授权、遥测和 VirtualService 等能力
流量路径:
- 只需要 L4 零信任时:源 Pod → 源节点 ztunnel → HBONE → 目标节点 ztunnel → 目标 Pod
- 需要 L7 时:源 ztunnel 把流量送到目标侧的 waypoint,waypoint 执行 L7 策略后再转发给目标
- waypoint 是否在路径上取决于流量原始目标是 Service 还是 Pod IP,以及
istio.io/waypoint-for。如果流量原始目标是 Service,而该 Service 没有 waypoint,即使后端 Pod 有 waypoint,流量也不会经过它;只有直接访问 Pod IP 且waypoint-for允许 workload 流量时,才会走 Pod 关联的 waypoint
HBONE 与节点内重定向
HBONE(HTTP-Based Overlay Network Environment)不是新造的车轮,而是三个标准的组合:
- HTTP/2:多路复用,把多条应用 TCP 流复用到一个加密连接上。
- HTTP CONNECT:建立隧道。
- mTLS:加密并验证双方工作负载身份。
默认监听 TCP 15008。它的关键属性是不修改应用流量本身:连接元数据放在 CONNECT 头里,不需要往业务请求中注入 Istio 私有 header。因此应用看到的仍是原始协议,代理可以在不改代码的情况下完成 mTLS 和身份传递。
Ambient 的重定向由 istio-cni 与 ztunnel 协作完成:
istio-cni作为 chained CNI 插件,在主 CNI 之后执行,监听 Pod 创建/删除。- ztunnel 在应用 Pod 的网络命名空间内建立捕获规则,因此不需要替换集群 CNI。
- 入站流量 TPROXY 到
15006,出站流量 REDIRECT 到15001,HBONE 走15008。 - 同节点 Pod 到 Pod 的流量也会经过本节点 ztunnel,保证 L4 授权和遥测对本地/跨节点流量一致。
ztunnel 通过 xDS 从 istiod 获取配置,并获取本节点上所有 Pod 的 ServiceAccount 证书。这解释了 Ambient 的资源模型:证书和配置集中在节点级代理,省掉了每 Pod 一份代理,但也把信任和故障集中到了节点。
Ambient 相关标签:
| 标签 | 作用 | 资源 |
|---|---|---|
istio.io/dataplane-mode=ambient |
加入 Ambient 网格 | Namespace / Pod |
istio.io/dataplane-mode=none |
Pod 级别退出 | Pod |
istio.io/use-waypoint=<name> |
流量经过指定 waypoint | Namespace / Service / Pod |
istio.io/ingress-use-waypoint=true |
入口流量也经过目标 waypoint,需要 istiod 开启 ENABLE_INGRESS_WAYPOINT_ROUTING(1.25+) |
Namespace / Service / ServiceEntry |
istio.io/waypoint-for(Alpha) |
waypoint 处理 service、workload、none 或 all 流量 |
Gateway |
waypoint 的作用域、策略与金丝雀
waypoint 是 Envoy Deployment,但它的行为更像“资源网关”:
- 只接收 HBONE:waypoint 不接受普通明文流量;源 ztunnel 负责把流量升级为 HBONE 后再送入。
- 策略在目的地执行:这是 Ambient 与 Sidecar 最大的语义差异。Sidecar 在源端和目标端都可能有策略执行点;Ambient 的 L7 策略由目标 waypoint 执行。对 Service,waypoint 还会执行路由和负载均衡;对 Pod,执行策略后直接转发。
- 作用域:
istio.io/use-waypoint可以打在 Namespace、Service 或 Pod 上。大多数场景按命名空间共享,减少 waypoint 数量。 - 流量类型:
istio.io/waypoint-for决定处理service、workload、all还是none,默认service。选择依据是流量最初寻址的目标类型;如果访问的是没有 waypoint 的 Service,即使后端 Pod 有 waypoint,也不会经过它。 - 入口流量:
istio.io/use-waypoint默认只管东西向;Ingress Gateway 到 Service 的流量默认不经过 waypoint。要经过,需在 Service/Namespace 上设置istio.io/ingress-use-waypoint=true,并让 istiod 开启ENABLE_INGRESS_WAYPOINT_ROUTING(默认false)。这会产生“入口网关 + waypoint”的两级 L7 处理,延迟、指标和授权都要按两跳设计。 - 金丝雀:1.31 支持把 Service 的流量按权重分给主 waypoint 和 canary waypoint,使用
istio.io/use-waypoint-canary、istio.io/use-waypoint-canary-namespace和istio.io/use-waypoint-canary-weight。waypoint 升级可以先切 5%,验证后再全量。 - 容量与爆炸半径:waypoint 是共享组件,一个副本挂掉会影响其作用域内所有服务。按安全边界拆分,配置 HPA、PDB、反亲和和资源 requests/limits;不要为了省资源把不相关部门塞进同一个 waypoint。
还有一个必须验证的边界:当前官方文档明确说明,来自 Sidecar 和 Gateway 的流量不会经过 waypoint(未来版本会补齐);网格外流量也不知道 waypoint 的存在,会直接访问目的地。混合数据面迁移时,这会造成“策略看起来配置了,但某类流量没经过执行点”的假象。
Ambient 的限制
- 只用 ztunnel 时只有 L4 能力;VirtualService、L7 授权、JWT、Wasm、L7 遥测都需要 waypoint。
- ztunnel 是节点级单点,节点故障会影响该节点全部 Ambient Pod 的连通性。
- 节点级多租户共享 ztunnel,隔离强度低于每 Pod Sidecar;高合规场景要单独评估。
dataplane-mode、use-waypoint、ingress-use-waypoint目前是 Beta,waypoint-for是 Alpha;生产使用前确认版本和升级说明。- Ambient 的多集群能力与 Sidecar 不完全等价,落地前按当前版本的官方支持矩阵验证。
Sidecar 与 Ambient 可以共存,但同一个命名空间不建议混用;如果同时命中,Sidecar 优先级更高。
Sidecar 与 Ambient 对比
| 维度 | Sidecar | Ambient |
|---|---|---|
| 代理位置 | 每个 Pod 一个 Envoy | 每节点 ztunnel,按需 waypoint |
| L4 能力 | 完整 | ztunnel 提供 |
| L7 能力 | 完整 | 需要 waypoint |
| 应用侵入 | 注入 Sidecar,需要重启 | 加标签,通常无需重启 |
| 资源开销 | 随 Pod 数增长 | ztunnel 随节点数增长 |
| 成熟度 | 最成熟 | 已可用;dataplane-mode、use-waypoint、ingress-use-waypoint 为 Beta,waypoint-for 为 Alpha |
| 适用场景 | 功能要求完整、存量系统 | 大规模、渐进接入、L4 为主 |
网关
- Ingress Gateway:集群入口,替代或补充 Kubernetes Ingress
- East-West Gateway:多集群之间的东西向流量
- Egress Gateway:统一出口,配合 NetworkPolicy 才能真正限制外联
网关本身也是 Envoy Deployment,可以独立扩缩容、独立升级。生产环境建议把入口和出口网关分开部署,不要复用同一个网关。
安装与接入
前置检查
- Kubernetes 版本在 Istio 支持范围内
- 集群有足够的 CPU/内存给 istiod 和网关
- 确认 CNI 方案,避免与 istio-cni 冲突
- 使用 Gateway API 时先安装对应 CRD,Gateway API CRD 默认不会随集群安装
- 规划命名空间、revision 和网关暴露方式
使用 istioctl 安装
curl -sL https://istio.io/downloadIstioctl | sh - |
生产环境不要直接用 demo profile。常用 profile:
| profile | 用途 |
|---|---|
default |
生产基础组件 |
demo |
学习与演示,包含较多组件 |
minimal |
只安装控制面 |
ambient |
安装 Ambient 所需组件 |
remote |
远程集群数据面 |
empty |
完全自定义 |
安装完成后给命名空间打注入标签:
kubectl label namespace default istio-injection=enabled |
使用 Helm 安装
helm repo add istio https://istio-release.storage.googleapis.com/charts |
Ambient 模式需要给 istiod 和 cni 指定 ambient profile:
helm install istio-base istio/base -n istio-system --create-namespace |
具体 values 以对应版本的官方 Helm 文档为准。
Sidecar 注入
自动注入依赖命名空间标签或 Pod 注解:
# 使用默认 revision |
注意:istio-injection 和 istio.io/rev 不要同时使用。两者同时存在时,istio-injection 优先,istio.io/rev 会被忽略。
单个 Pod 可以覆盖:
metadata: |
手动注入用于调试或特殊场景。使用 revision 安装时必须指定 revision,否则可能注入到默认控制面或直接失败:
istioctl kube-inject -f deployment.yaml --revision=1-31-3 | kubectl apply -f - |
验证注入结果:
kubectl get pod -n prod -o jsonpath='{.items[*].spec.containers[*].name}' |
Ambient 接入
istioctl install --set profile=ambient -y |
只需要 L4 能力时可以不部署 waypoint。需要 L7 路由、JWT 或 L7 授权时,再为命名空间、Service 或 Pod 部署 waypoint。
升级与 revision
推荐使用 revision 做金丝雀升级,而不是直接原地覆盖:
# 安装新 revision,旧控制面继续服务 |
升级顺序:
- 备份 Istio 与业务相关 CRD 配置
- 运行
istioctl x precheck检查环境兼容性 - 升级控制面
- 用
istioctl analyze -A检查配置 - 按命名空间切换数据面
- 用
istioctl proxy-status确认全部SYNCED - 观察错误率、延迟和 mTLS 指标后再删除旧 revision
回滚时把命名空间的 istio.io/rev 切回旧 revision,并重启工作负载即可。
注意:istioctl upgrade 只用于原地升级,不兼容使用 --revision 安装的集群。revision 安装请继续使用 istioctl install --set revision=...。
卸载
istioctl uninstall -y |
不加 --purge 时 CRD 会保留。--purge 会删除所有 Istio 资源,包括可能与其他控制面共享的集群级资源,执行前务必确认。istio-system 命名空间不会自动删除,需要单独执行。
流量管理
核心对象
| 对象 | 作用 |
|---|---|
Gateway |
入口/出口监听与 TLS 配置 |
VirtualService |
路由规则:匹配、重写、重试、超时、故障注入、镜像 |
DestinationRule |
目标服务策略:subset、负载均衡、连接池、熔断、TLS |
ServiceEntry |
把外部服务注册进网格 |
Sidecar |
限制 Sidecar 订阅的配置范围,降低 xDS 压力 |
WorkloadEntry |
把 VM 等工作负载注册进网格 |
WorkloadGroup |
批量管理 WorkloadEntry |
路由匹配、作用域与合并
流量管理的难点不在字段,而在“哪条规则最终生效”。一条请求至少经过四层决策:
谁发的(Sidecar / Gateway / waypoint) |
几个容易出错的语义:
- host 解析:
reviews、reviews.default、reviews.default.svc.cluster.local可能指向不同范围;跨命名空间时写全限定名,避免歧义。 - 作用域优先级:Sidecar/工作负载级 > 命名空间级 > mesh 级;入口网关规则只作用于绑定的 Gateway。
- **
exportTo**:控制资源对哪些命名空间可见;被排除的命名空间看不到该路由/服务,表现为“配置没生效”或 503,而不是自动拒绝。 - **
Sidecar**:限制代理订阅范围,减少 xDS;它不是访问控制,未列出的目标仍可能按默认行为访问。 - 合并:同一 host 的多个 DestinationRule 会合并,但重复 subset 只保留第一个;建议一个 host 一个 DestinationRule,subset 名称唯一。
- 默认路由:Istio 默认会把流量发给服务的所有版本。上线新版本前先写默认路由,否则新 Pod 可能立即接流量。
- make-before-break:先加 subset,再切流量,最后删旧 subset;反过来会出现指向不存在上游的 503。
调试时不要只看 CRD,要看代理视角:
istioctl proxy-config route <pod> -n <ns> --name 80 |
Gateway API 与 Istio Gateway
Istio 同时支持:
- Istio Gateway + VirtualService:存量配置多,功能完整
- Kubernetes Gateway API:
GatewayClass、Gateway、HTTPRoute、GRPCRoute,更符合 Kubernetes 生态
新项目优先使用 Gateway API;已有 Istio Gateway 不需要立刻迁移。
Gateway API 示例:
apiVersion: gateway.networking.k8s.io/v1 |
Gateway API 的关键语义
Gateway API 有两套使用方式,不要混为一谈:
- 入口:
GatewayClass+Gateway+HTTPRoute。Gateway代表一个负载均衡器/监听器,HTTPRoute通过parentRefs绑定到它。 - 网格:GAMMA 模型。
HTTPRoute直接把parentRefs指向 Service,不使用Gateway/GatewayClass。这是 Mesh 场景的 GA 能力。
关键字段:
| 字段 | 作用 |
|---|---|
parentRefs[].name/namespace |
绑定到 Gateway 或 Service;跨命名空间需要 ReferenceGrant |
parentRefs[].sectionName |
只绑定某个 listener |
hostnames |
匹配的域名 |
rules[].matches |
path/header/query/method 匹配 |
rules[].backendRefs |
后端 Service/端口/权重 |
allowedRoutes |
Gateway 允许哪些命名空间的 Route 绑定 |
status.parents[].conditions |
是否被接受、为什么被拒绝 |
实践建议:
- 新项目优先 Gateway API,存量 Istio Gateway 不必立刻迁移。
Gateway的hosts/hostname要收紧,不要用*。- 跨命名空间引用用
ReferenceGrant显式授权,不要靠“同集群默认可达”。 - Gateway API CRD 版本必须满足 Istio 要求;1.31 的
istioctl analyze会用IST0176提示 CRD 版本过低,低于要求的资源会被 istiod 静默过滤。 - 入口用
gatewayClassName: istio;Ambient waypoint 用istio-waypoint,两者不要混用。
VirtualService 原理
VirtualService 负责“请求怎么走”。匹配顺序是:
- 按
hosts选中服务 - 按
http.match从上到下匹配,第一条命中即生效 - 命中后按
route选择目标 subset 和权重 - 没有命中任何
match时走默认路由
常用字段:
hosts:作用于哪些服务gateways:绑定入口网关;不写表示网格内部http.match:按 URI、header、method、query 匹配http.route:目标 subset 和权重rewrite、retries、timeout、fault、mirror
灰度示例:
apiVersion: networking.istio.io/v1 |
注意:DestinationRule 中的 subset 策略只有在 VirtualService 明确路由到该 subset 时才生效。只定义 DestinationRule、不定义路由时,subset 的流量策略不会自动应用。
DestinationRule 原理
DestinationRule 负责“到目标怎么连”。
apiVersion: networking.istio.io/v1 |
loadBalancer:ROUND_ROBIN、LEAST_REQUEST、LEAST_CONN、RANDOM、PASSTHROUGHconnectionPool:限制连接数、等待请求数,配合熔断outlierDetection:连续错误达到阈值后把实例摘除一段时间trafficPolicy.tls:配置到上游的 TLS
同一 host 的多个 DestinationRule 会被合并,但同名 subset 以第一个定义为准,后续重复会被丢弃;top-level trafficPolicy 也只保留第一个被处理的,后续丢弃。跨资源顺序未定义主要针对绑定 Gateway 的 VirtualService 分片,不适用于 DestinationRule。建议一个 host 只用一个 DestinationRule,并保证 subset 名称唯一。
负载均衡、locality 与后端健康
负载均衡算法只是“选谁”,真正决定可用性的是“谁还在池子里”:
| 算法 | 适用 | 注意 |
|---|---|---|
ROUND_ROBIN |
同构后端、请求成本均匀 | 长连接下容易不均 |
LEAST_REQUEST |
请求成本差异大 | 需要代理维护活跃请求数 |
LEAST_CONN |
TCP 为主 | 对 HTTP/2 多路复用不敏感 |
RANDOM |
大规模、实现简单 | 方差较大 |
PASSTHROUGH |
直接透传 | 不做负载均衡,慎用 |
| 一致性哈希 | 会话保持、缓存亲和 | 后端增减会重排,需评估缓存命中 |
再叠加两层策略:
- Locality LB:优先同区域/同 AZ,失败再跨区;
failoverPriority控制跨区顺序。跨区调用会增加延迟和出口成本,不能只看“能不能通”。 - Panic threshold:健康后端比例低于阈值时,Envoy 可能进入 panic 模式,把流量打向所有后端(包括不健康的),这是 fail-open 设计,不是 bug。要理解它和
outlierDetection的交互。
后端健康由三部分共同决定:
- Kubernetes readiness / EndpointSlice 状态。
outlierDetection的被动驱逐(连续 5xx、网关错误等)。minHealthPercent等健康阈值。
1.31 的一个行为变化:**默认会发送不健康的 Endpoint,除非配置了 OutlierDetection.minHealthPercent**。这会影响“后端不健康时是否继续接流量”的预期,升级前要确认;可以用 PILOT_AUTO_SEND_UNHEALTHY_ENDPOINTS=false 或兼容 profile 回退。
1.31 还增加了 zone-aware 负载均衡能力,依赖 failoverPriority 分层,并且需要 ISTIO_META_ENABLE_SELF_DISCOVERY: "true" 注入本地 cluster 信息;该能力目前仅支持 Sidecar 模式,Ambient 不支持。
灰度与发布
常见方式:
- 按权重:90/10、50/50,逐步放量
- 按请求头:内部用户或测试账号优先命中新版本
- 按 URI:新接口先走新版本
- 流量镜像:把生产流量复制到新版本,不影响主链路
发布顺序建议“make-before-break”:
- 先更新 DestinationRule,增加新 subset
- 再更新 VirtualService,把少量流量切到新 subset
- 观察指标和日志
- 逐步放量
- 稳定后再删除旧 subset
如果先改 VirtualService 再改 DestinationRule,Envoy 可能引用不存在的上游,期间返回 503。
超时、重试与熔断
http: |
重试放大与超时预算
重试不是“更可靠”,而是“用更多流量换一次机会”。假设单次失败率 10%,最多重试 3 次(共 4 次尝试):
- 最终失败率:
1 - 0.9^4 = 34.4%。 - 期望尝试次数:
1 + 0.1 + 0.01 + 0.001 = 1.111,即额外 11.1% 负载。
如果失败原因是过载,重试会进一步压垮下游,形成重试风暴。只对幂等、瞬时、可重放的失败重试;写操作必须有幂等键。
超时是端到端预算,不是每跳拍脑袋:
调用方剩余 deadline |
Istio 的 timeout 是这条路由的总超时,重试通常也消耗这个预算;perTryTimeout 是单次尝试的上限。两者必须满足 perTryTimeout × (attempts + 1) ≤ timeout,否则后面的重试没有意义。同时,超时不能小于被调服务的正常处理时间,否则会稳定 504。
retryOn 要按错误类型选择,不要无脑 5xx:
connect-failure、reset、refused-stream:连接层瞬时故障,通常可重试。5xx、gateway-error:可能是业务错误,也可能是过载;配合幂等和错误预算。retriable-4xx:只对特定 4xx 有意义,慎用。retryRemoteLocalities:跨区重试会增加延迟和出口成本。
熔断:连接池 + 异常点驱逐
熔断不是单一开关,而是两层:
- 连接池限制:
maxConnections、http1MaxPendingRequests、http2MaxRequests、maxRetries。过载时快速失败,避免请求无限排队。 - 异常点驱逐:
outlierDetection根据连续错误把后端摘除一段时间。
trafficPolicy: |
要点:
maxEjectionPercent太低,坏后端仍会接流量;太高,可能把池子踢空。minHealthPercent决定健康后端不足时的行为,和 1.31 的默认发送不健康 Endpoint 变化直接相关。- 驱逐是被动的,恢复依赖时间窗口;快速抖动场景要配合主动健康检查和合理的超时。
- 重试、熔断、限流要一起设计;只加重试等于给故障加杠杆。
故障注入与镜像
http: |
流量镜像:
http: |
故障注入适合做混沌演练,但不要在入口网关对全量流量开启,容易造成真实故障。
ServiceEntry 与出口流量
把外部服务注册进网格:
apiVersion: networking.istio.io/v1 |
出口治理建议:
meshConfig.outboundTrafficPolicy.mode: REGISTRY_ONLY可以阻止未声明的外联,但不是强安全边界- 真正要限制外联时,使用 Egress Gateway + NetworkPolicy,确保流量不能绕过代理
- 对敏感出口统一做 TLS 源、审计和访问控制
ServiceEntry 的解析模式
resolution 决定代理如何得到后端地址:
| 模式 | 行为 | 适用 |
|---|---|---|
NONE |
直接把原始目标 IP 交给应用/代理,不做端点列表 | 外部 API、需要保持原目标 |
STATIC |
使用 spec.endpoints 中的静态地址 |
固定 IP 的外部服务、VM |
DNS |
代理周期性解析域名,再负载均衡 | 动态 DNS、外部服务 |
resolution: DNS 的细节很重要:Istio 代理不会在请求时同步解析 DNS,而是每 30 秒周期性解析(当前固定值),即使没有请求也会解析。代理数量多、TTL 低时,会给 DNS 服务器造成明显压力。优化手段:
- 能用
NONE就用NONE,避免代理侧 DNS 轮询。 - 自己控制的域名提高 TTL。
- 用
exportTo或Sidecar把ServiceEntry限制到真正需要它的工作负载。
DNS 代理(ISTIO_META_DNS_CAPTURE)只捕获应用发出的 DNS 请求,让 ServiceEntry 的域名可以被解析;它不影响 resolution: DNS 时代理自己的解析路径。需要自动分配地址时使用 ISTIO_META_DNS_AUTO_ALLOCATE。
出口网关与强制路径
REGISTRY_ONLY 只能减少“意外外联”,不是强安全边界:绕过 Sidecar 的流量仍可能出网。真正要强制出口路径,需要:
ServiceEntry登记外部依赖。- Egress Gateway 承载出口流量。
- NetworkPolicy 只允许工作负载访问 Egress Gateway,禁止直连外部。
- 在网关上做 TLS 源、审计、限流和授权。
TLS 源(origination)场景要确认 SNI、证书校验和 DNS 解析都正确;只配 tls.mode: SIMPLE 而不校验上游证书,等于把 mTLS 的收益丢掉一半。
1.31 新增的 serviceEntryVisibility 可以控制 ServiceEntry 对哪些命名空间/工作负载可见;Ambient 默认强制执行,Sidecar 需要 applyToSidecars。这适合平台团队把外部依赖收口,但也会让“看不到”表现为解析失败或 503,变更前要评估。
Sidecar 配置范围
大型集群里,每个 Sidecar 默认可能看到大量服务,导致 xDS 配置膨胀。可以用 Sidecar 限制订阅范围:
apiVersion: networking.istio.io/v1 |
这表示 prod 的 Sidecar 只订阅本命名空间和 istio-system 的配置。未包含的目标会按 unmatched traffic 处理,通常仍然可以访问,Sidecar 本身不能强制阻断出站。要阻断出站请用 Egress Gateway、NetworkPolicy 或 AuthorizationPolicy。跨命名空间调用若希望保留 L7 配置(超时、重试、subset),需要显式加入对应 host。
网关 TLS
- TLS 终止:客户端到网关用 HTTPS,网关到后端可用 HTTP 或 mTLS
- TLS 透传:网关不终止 TLS,适合需要端到端加密的场景
- 证书建议由 cert-manager 或企业 CA 统一签发和轮换
Gateway.servers[].hosts不要使用*,按域名或命名空间收紧- 入口网关和出口网关分开部署,分别扩缩容
多集群与多网络
单集群 Mesh 是常态,多集群才是架构分水岭。多集群不是为了“看起来高可用”,而是为了故障隔离、地域合规、就近访问、迁移过渡和爆炸半径控制。
网络模型
| 模型 | 连通性 | 服务发现 | 适用 |
|---|---|---|---|
| 单网络 | 所有 Pod 可直接互通 | 扁平发现,所有 Endpoint 可见 | 同 VPC、多集群但网络已打通 |
| 多网络 | 跨网络只能经 Gateway | 分区发现,按消费者网络返回不同 Endpoint | 跨云、跨地域、网络隔离 |
单网络的前提是 Pod/Service IP 不重叠。多网络下,Istio 只支持“跨网络访问有 Istio 代理的工作负载”,因为网关用 TLS 透传把 mTLS 直接延伸到工作负载;没有代理的工作负载无法参与双向认证。
控制面模型
- Primary-Remote:一个主集群运行 istiod,远程集群只跑数据面。运维简单,但控制面跨网络依赖强,主集群故障影响面大。
- Multi-Primary:每个集群都有自己的 istiod,互相发现。故障隔离更好,但要处理配置一致性、信任域和版本偏差。
- External Control Plane:控制面独立于数据面集群,适合托管/多租户平台。
不管哪种模型,都要明确:
- 哪个集群是配置源?GitOps 如何避免两个控制面互相覆盖?
- 控制面版本是否一致?数据面允许的版本偏差是多少?
- 跨集群的
ServiceEntry、AuthorizationPolicy、Sidecar如何分发?
命名空间同名合并
多集群中,同名命名空间默认被视为同一个命名空间。例如 West/Team-1 和 East/Team-1 中的同名 Service 会合并 Endpoint,参与同一套负载均衡。这既是便利,也是风险:
- 两个团队碰巧用了同一个命名空间名,可能意外互通。
- 迁移期同名服务可能把流量吸到错误集群。
- 需要隔离时,使用不同命名空间名、
exportTo、discoverySelectors和 AuthorizationPolicy。
信任域与证书
跨集群 mTLS 的核心是信任:
- 同一个 CA、同一个 trust domain:最简单,证书天然互信。
- 不同 CA/trust domain:需要交换 trust bundle,可以用 SPIFFE Trust Domain Federation,或手工分发根证书。
- 不同信任域之间,授权策略要显式处理 principal;1.31 的
AuthorizationPolicy.source.trustDomains/notTrustDomains可以按信任域匹配或排除。
不要让“能通”掩盖“身份不对”:跨集群 200 响应不代表授权模型正确,必须验证 principal 和 trust domain。
East-West Gateway
多网络场景下,跨集群流量通常经 East-West Gateway:
Cluster A Pod → A 侧 Sidecar → East-West Gateway A |
要点:
- 网关要支持 TLS 透传,才能把 mTLS 延伸到工作负载,而不是在网关终止后重新发起。
- 网关容量按跨集群峰值流量规划,独立于入口网关。
- 跨网络多一跳,超时、重试和熔断预算要重新计算。
- 网络分区时,要明确“本地优先、跨区 failover”还是“直接失败”,不要依赖默认行为。
多集群故障模式
| 故障 | 表现 | 排查 |
|---|---|---|
| 跨集群 Endpoint 不出现 | 只看到本集群后端 | 检查远程 secret、istioctl remote-clusters、网络连通性 |
| 证书/信任域不匹配 | 跨集群 503 TLS error | 对比根证书、trust domain、proxy-config secret |
| 同名命名空间误合并 | 流量跑到错误集群 | 检查命名空间命名和 Endpoint |
| East-West Gateway 过载 | 跨区延迟/超时 | 网关副本、连接数、CPU、限流 |
| 控制面分区 | 两侧配置不一致 | 版本、GitOps 同步、proxy-status |
| DNS 解析不一致 | 同一域名不同结果 | 检查 DNS 代理、ServiceEntry、CoreDNS |
Ambient 的多集群支持仍在演进,落地前要以当前版本的官方支持矩阵为准;不要假设它与 Sidecar 多集群完全等价。
安全
图 4:Istio 官方安全架构总览
身份与证书原理
Istio 以 ServiceAccount 为粒度分配 SPIFFE 身份,同一 ServiceAccount 下的所有工作负载共享该身份:
spiffe://cluster.local/ns/<namespace>/sa/<service-account> |
如果需要隔离身份,必须为不同工作负载使用不同的 ServiceAccount。
证书签发流程:
- Istio agent 生成私钥和 CSR
- agent 带着 ServiceAccount 凭证向 istiod 请求签名
- istiod 校验凭证后签发证书
- Envoy 通过 SDS 从 agent 获取证书和私钥
- agent 监控证书有效期并自动轮换
图 5:Istio 官方身份与证书签发流程
生产环境可以通过 istio-csr 接入 cert-manager 或 Vault,或挂载企业 CA 的 cacerts Secret。cert-manager 本身是证书管理控制器,不是 CA。
证书生命周期与 CA 选型
Istio 默认给工作负载签发短生命周期证书(常见默认 24 小时,可配置),istio-agent 在过期前自动轮换。这个模型的安全收益是“密钥暴露窗口小”,代价是控制面和 CA 必须持续可用。
CA 选型:
| 方式 | 特点 | 适用 |
|---|---|---|
| 自签 CA(默认) | 开箱即用,istiod 持有根证书 | 测试、简单集群 |
挂载 cacerts |
使用企业 CA 的根/中间证书 | 已有 PKI、需要统一信任根 |
| istio-csr + cert-manager | 由 cert-manager 签发,支持 Vault/外部 issuer | 企业 PKI、自动化轮换 |
| 外部 SPIFFE/CA | 与组织身份体系集成 | 多网格、强合规 |
证书运维的硬要求:
- 根证书轮换:必须先让新旧根证书同时被信任,再逐步换发工作负载证书,最后移除旧根;直接替换会导致全网格握手失败。
- TTL 与提前量:TTL 越短越安全,但对 CA 可用性要求越高;至少保留多个轮换周期的余量。
- 时钟:节点时间漂移会让证书“尚未生效/已过期”,mTLS 直接 503;NTP 是 Mesh 的基础设施。
- CA 故障演练:istiod 全挂时,已有证书在 TTL 内仍可用;但 TTL 到期后会集中失败。要演练 CA 恢复和批量轮换。
- 监控:证书到期时间、CSR 成功率、轮换失败、istiod CA 错误率都要告警。
1.31 新增 FIPS 140-3 合规策略(COMPLIANCE_POLICY=fips-140-3),会限制 TLS 版本、密码套件和曲线,并要求 Go 组件以相应方式构建。金融/政府场景不要只开开关,要验证 Envoy、istiod、证书链和上游服务全部满足要求。
mTLS 原理
mTLS 是双向认证:客户端和服务端都要出示证书,并校验对方的证书链和 SPIFFE 身份。Istio 默认自动为网格内流量升级到 mTLS。
图 6:Istio 官方认证架构:传输认证与来源认证
PeerAuthentication 控制目标工作负载接受哪种流量:
apiVersion: security.istio.io/v1 |
模式:
PERMISSIVE:同时接受 mTLS 和明文,适合迁移期STRICT:只接受 mTLSDISABLE:关闭 mTLS,不建议使用
迁移顺序:
- 保持
PERMISSIVE - 把所有客户端接入网格
- 查看
istio_requests_total{connection_security_policy="mutual_tls"}与connection_security_policy="unknown"的比例,确认明文流量归零 - 按命名空间或工作负载切到
STRICT - 观察错误率,确认后再扩大范围
可以按端口覆盖:
portLevelMtls: |
mTLS 验证与失败模式
不要用“服务能通”证明 mTLS 生效。至少验证三件事:
- 连接安全策略:
istio_requests_total{connection_security_policy="mutual_tls"}的比例;unknown代表明文或未识别。 - 证书身份:
istioctl proxy-config secret <pod>看证书链、SAN、有效期;istioctl x describe pod看工作负载身份和 mTLS 状态。 - 策略结果:从不同命名空间/不同 ServiceAccount 发起请求,确认该拒绝的被拒绝。
常见 503/TLS 失败:
| 现象 | 根因 |
|---|---|
切 STRICT 后部分调用 503 |
仍有客户端没有 Sidecar,或走了明文 |
| 全网格突然 TLS 失败 | 根证书/中间证书过期,或轮换不完整 |
| 跨集群 TLS 失败 | trust domain/根证书不一致 |
| 单服务 TLS 失败 | PeerAuthentication 的端口/selector 覆盖错误 |
| 证书 SAN 不匹配 | 授权 principal 写错,或 ServiceAccount 不一致 |
| 时间相关失败 | 节点时钟漂移,证书未生效/已过期 |
再强调一次:mTLS 只提供传输层身份认证,不提供授权。开了 STRICT 但没有 AuthorizationPolicy,任何持有合法证书的工作负载仍然可以访问。
JWT 认证
RequestAuthentication 校验终端用户 JWT:
apiVersion: security.istio.io/v1 |
RequestAuthentication 会拒绝携带无效凭证的请求;完全不带凭证的请求默认放行,但没有认证身份。要强制要求 JWT,必须再配合 AuthorizationPolicy 的 requestPrincipals。
JWT 的边界与细节
RequestAuthentication 只做“凭证校验”,不做“是否允许访问”。它的典型配置项:
- issuer:必须与 token 的
iss完全匹配。 - jwksUri:公钥地址;istiod/代理会缓存并周期刷新,JWKS 不可达会导致新 token 无法验证。
- audiences:校验
aud,不要只验签名。 - fromHeaders / fromParams / fromCookies:token 从哪里取;默认
Authorization: Bearer。 - forwardOriginalToken:是否把原始 token 继续转给上游。
- outputPayloadToHeader:把解析后的 claims 放到指定 header,供上游使用;注意不要泄露敏感 claim。
- timeout:JWKS 获取/校验的超时。
校验通过后,request.auth.claims[...] 可用于 AuthorizationPolicy 的 when 条件;requestPrincipals 是 issuer/subject 组成的身份。JWT 的签名、过期、issuer、audience 任何一项不满足都应拒绝,不能只验“有没有 token”。
授权原理
AuthorizationPolicy 支持 ALLOW、DENY、AUDIT、CUSTOM。评估顺序是 CUSTOM → DENY → ALLOW:
- 命中
DENY直接拒绝 - 如果有
ALLOW策略,未命中任何ALLOW的请求被拒绝 - 如果没有
ALLOW策略,默认允许,除非命中DENY
图 7:Istio 官方授权评估顺序
默认拒绝示例:
apiVersion: security.istio.io/v1 |
只允许带合法 JWT 的 GET 请求:
apiVersion: security.istio.io/v1 |
企业实践:
- 使用
ALLOW+ 正向匹配,或DENY+ 负向匹配,避免策略绕过 - 不要用过于宽泛的
paths: ["/*"]和methods: ["*"] - 健康检查、指标端口单独放行
- 策略变更先在测试命名空间验证,再通过 GitOps 推广
授权语义与边界
AuthorizationPolicy 的评估顺序是 CUSTOM → DENY → ALLOW:
- 命中
DENY立即拒绝,优先级最高。 - 如果有
ALLOW策略,未命中任何ALLOW的请求被拒绝。 - 如果没有任何
ALLOW策略,默认允许(除非命中DENY)。
所以“默认拒绝”必须显式创建一条空规则:
apiVersion: security.istio.io/v1 |
常用匹配维度:
| 维度 | 字段 | 注意 |
|---|---|---|
| 工作负载身份 | principals / notPrincipals |
SPIFFE 格式,注意 trust domain |
| 信任域 | trustDomains / notTrustDomains(1.31) |
跨集群/多 CA 场景 |
| 命名空间 | source.namespaces |
比 IP 稳定 |
| IP | remoteIpBlocks / ipBlocks |
经过代理后是代理 IP,慎用 |
| 方法/路径 | methods / paths |
注意路径规范化、编码、尾斜杠 |
| JWT claims | request.auth.claims[...] |
需要 RequestAuthentication |
| 条件 | when |
key 如 request.headers[...]、source.ip |
几个容易写错的地方:
paths: ["/api/*"]的匹配语义受实现和规范化影响,管理接口要单独列出并默认拒绝。- 只写
ALLOW不允许任何未匹配请求,但如果没有ALLOW,默认是允许;不要以为“加了策略就默认拒绝”。 DENY适合做“黑名单/兜底”,ALLOW适合做“白名单”;混用时先想清楚优先级。CUSTOM走外部授权服务(ext_authz),要设计超时、失败开放/关闭和缓存,否则外部服务抖动会放大为全站故障。AUDIT只记录不阻断,适合上线前观察策略命中情况。
Ambient 中,L4 策略由 ztunnel 执行,L7 策略由目标 waypoint 执行。从 1.25 起可以用 targetRefs 把策略绑定到 istio-waypoint GatewayClass,实现 waypoint 级默认拒绝;这类策略必须放在 root namespace(通常是 istio-system),且 selector 与 targetRefs 二选一。
Ambient 下的安全
- ztunnel 负责 L4 mTLS、认证和 L4 授权
- L7 授权、JWT、VirtualService 需要 waypoint
- L4 策略由 ztunnel 执行,L7 策略由目标 waypoint 执行
- waypoint 是否在路径上取决于流量原始目标(Service 还是 Pod IP)以及
istio.io/waypoint-for - 从 Istio 1.25 起,可以把
AuthorizationPolicy通过spec.targetRefs绑定到istio-waypointGatewayClass,实现 waypoint 级别的默认拒绝。这类策略必须放在 root namespace(通常是istio-system),且selector与targetRefs二选一
安全落地顺序
- 全网格启用 mTLS,最终切到
STRICT - 默认拒绝,再按服务逐个放行
- 对外接口接入 JWT 或外部授权
- 收紧 Gateway
hosts,禁止通配符 - 出口统一走 Egress Gateway + NetworkPolicy
- 接入外部 CA,统一证书生命周期
- 限制 istiod 调试端口和集群内访问
威胁模型
| 威胁 | Istio 的控制 | 残余风险 |
|---|---|---|
| Pod 被攻破后横向扫描 | mTLS + L4/L7 授权限制可达服务 | 被攻破工作负载可用自己的合法身份访问被允许的服务 |
| 中间人窃听 | 自动 mTLS | 绕过代理的流量、网格外流量、网关终止后的明文段 |
| 身份伪造 | SPIFFE + 证书校验 | CA/控制面被攻破、节点 root、证书私钥泄露 |
| 未授权 API 调用 | AuthorizationPolicy + JWT | 策略写错、路径绕过、业务逻辑漏洞 |
| 供应链恶意镜像 | 镜像签名/准入控制(Mesh 之外) | Istio 不负责镜像可信 |
| 数据外泄 | ServiceEntry + Egress Gateway + NetworkPolicy | 直连 IP、DNS 隧道、被允许的外部服务 |
| 拒绝服务 | 连接池、熔断、限流 | Istio 不是抗 DDoS 设备 |
| 控制面被攻破 | 最小权限、调试端口认证、网络策略 | 可签发证书/推送配置,影响面接近全网格 |
Mesh 的安全价值是“把身份和策略变成默认路径”,不是“让应用自动安全”。应用自身的输入校验、权限模型、密钥管理仍然是第一道防线。
可观测性
指标原理
Envoy 在数据面统计请求量、延迟、错误和 TCP 指标,再暴露给 Prometheus。常见指标:
istio_requests_totalistio_request_duration_millisecondsistio_request_bytesistio_response_bytesistio_tcp_connections_opened_totalistio_tcp_connections_closed_total
这些指标带有 source_workload、destination_workload、response_code、reporter 等标签。reporter 区分 source 和 destination:同一笔请求会同时被源代理和目标代理统计,计算错误率时要明确用哪一侧,避免重复计算。
指标语义与排障
做 SLO 时先确定口径:
- source:调用方视角,适合衡量“用户/上游看到的成功率与延迟”。
- destination:服务端视角,适合衡量“服务实际处理了多少请求、失败在哪”。
- 两边都看,才能区分“请求没到”和“到了但失败”。
response_flags 比 HTTP 状态码更接近根因:
| flag | 含义 | 常见原因 |
|---|---|---|
UF |
upstream connection failure | 连接失败、端口错、mTLS 握手失败 |
UC |
upstream connection termination | 上游主动断开、超时、协议不匹配 |
UO |
upstream overflow | 连接池/熔断/队列溢出 |
UH |
no healthy upstream | 没有健康 Endpoint、readiness 失败 |
NR |
no route | host/route 不匹配 |
URX |
retry limit exceeded | 重试次数耗尽 |
- |
正常 | 无特殊事件 |
其他关键标签:
connection_security_policy="mutual_tls":确认 mTLS 是否真的生效。destination_service/destination_service_name:注意不同版本/指标的名称差异。request_protocol:HTTP/1.1、HTTP/2、gRPC、TCP。response_code:注意0表示无 HTTP 响应(如 TCP 或连接失败)。
延迟要看直方图/分位数,不要只看平均值。istio_request_duration_milliseconds 是直方图,配合 histogram_quantile 计算 P50/P90/P99;平均值会被长尾和采样掩盖。
控制面可观测性
数据面指标只能解释“请求发生了什么”,控制面指标解释“配置为什么没到”:
| 指标 | 用途 |
|---|---|
pilot_xds |
当前连接的代理数 |
pilot_xds_pushes |
按类型统计的推送次数 |
pilot_xds_push_time |
推送耗时分布 |
pilot_xds_push_context_errors |
推送上下文生成错误 |
pilot_xds_expired_nonce |
过期 nonce,通常意味着代理处理慢或推送积压 |
citadel_server_csr_count |
证书签发量 |
citadel_server_root_cert_expiry_timestamp |
根证书到期时间 |
控制面看板至少包含:istiod 副本数/CPU/内存、xDS 连接数、推送耗时 P99、NACK/STALE 数量、证书签发失败率、根证书剩余天数、webhook 延迟。
Telemetry API
telemetry.istio.io/v1 用于统一配置指标、日志和追踪,不再依赖旧版 EnvoyFilter。
减少指标标签示例:
apiVersion: telemetry.istio.io/v1 |
匹配与覆盖
Telemetry 资源可以按工作负载/命名空间选择器生效,也可以在 root namespace 配置全局默认。常见用法:
metrics[].overrides[]:按metric和mode(CLIENT/SERVER)覆盖标签。tagOverrides:删除高基数标签或重命名。accessLogging[]:启用/禁用访问日志,选择 provider。tracing[]:设置采样率和自定义 tag。
注意:
Telemetry的资源选择器和AuthorizationPolicy不同,它不影响安全,只影响遥测。- 覆盖标签会改变指标语义,改完后要同步更新看板和告警。
- 访问日志和追踪都有成本,按服务和错误率采样,不要全量。
SLO 与重试
重试会让“用户失败率”和“后端失败率”分叉:
- 后端 10% 失败,重试 3 次后用户失败率可能降到 34.4%,但后端承受了额外 11% 的尝试。
- SLO 应基于 source 侧的最终结果,同时单独监控 destination 侧的尝试级失败率。
- 错误预算要扣除重试放大带来的额外负载,否则会出现“SLO 达标但后端已过载”的假象。
建议同时建三块看板:
- 入口/核心服务 SLO:source 侧成功率、P99、流量。
- 依赖健康:destination 侧错误率、
response_flags、连接池。 - 控制面健康:xDS 同步、证书、webhook、推送延迟。
访问日志
通过 Telemetry API 开启:
apiVersion: telemetry.istio.io/v1 |
访问日志字段包括源/目标工作负载、响应码、耗时、上游地址、请求 ID 等。高流量服务要注意日志量和采样,避免磁盘和日志后端被打满。
链路追踪
- Istio 支持 W3C Trace Context、B3 等传播格式
- 后端可接 Jaeger、Tempo、Zipkin 或企业 APM
- 采样率通过 Telemetry API 或 meshConfig 配置
- 生产环境不要 100% 采样,按流量和排障需求调整
- 确保应用把 trace header 继续向下游传递
Kiali 与 Grafana
- Kiali:拓扑、配置校验、流量与错误可视化
- Grafana:Istio 标准仪表盘,观察延迟、错误率、mTLS 比例
- Prometheus:采集 Istio 标准指标和 Envoy 指标
指标基数治理
指标基数爆炸通常来自高基数标签,例如 URL、用户 ID、请求 ID。治理方式:
- 用 Telemetry API 删除不必要的标签
- 用 recording rules 做 workload 级别聚合
- 用 recording rules 预聚合后,再通过 federation 或 remote write 只保留聚合后的 series;federation 本身不做聚合
- 控制
istio_requests_total的维度,不要把所有业务标签都加到指标上
企业实践
版本与升级原则
- 控制面与数据面分开升级,使用 revision 做金丝雀。
- 关注 Istio 支持的 Kubernetes 版本和官方版本偏差策略,不要让偏差长期存在。
- 保留旧 revision 一段时间,确认稳定后再删除。
- 详细步骤、1.31 注意事项和故障域见 升级与故障学。
多租户与命名空间
- 一个团队一个命名空间,Sidecar 注入、NetworkPolicy、配额都在命名空间维度管理
- 用
Sidecar资源限制每个命名空间订阅的配置,降低 xDS 压力;它不是访问控制 - 用
discoverySelectors控制 istiod 只发现指定命名空间。它只影响配置发现,不是网络隔离或授权;排除命名空间后,跨命名空间访问可能表现为无配置或 503 - 用 NetworkPolicy 限制跨命名空间访问,不要只依赖 AuthorizationPolicy
- 网关按业务域拆分,避免所有团队共用一个入口网关
配置管理
- 所有 Istio CRD 纳入 GitOps,禁止手工
kubectl edit - 每个服务从第一天就配置默认路由,避免新版本上线后自动接流量
- 新增 subset 遵循 make-before-break
- 大型 VirtualService/DestinationRule 按团队或服务拆分,避免单文件冲突
- 同一 host 的多个 DestinationRule 会被合并,但同名 subset 以第一个为准,重复定义被丢弃;建议一个 host 只用一个 DestinationRule
- CI 中执行
istioctl analyze,把配置错误拦在合并前
网关实践
- 入口和出口分开部署,独立 HPA 和资源配额
Gateway.servers[].hosts只写明确域名,禁止*- TLS 证书由 cert-manager 或企业 CA 管理,设置到期告警
- 入口网关不要暴露 admin/debug 端口
- 多集群场景使用 East-West Gateway,东西向流量单独规划
- 网关的副本数、连接数和 CPU 要按峰值流量压测
性能与容量
延迟路径
| 模式 | 请求路径 | 额外跳数 |
|---|---|---|
| 无 Mesh | 应用 → 应用 | 0 |
| Sidecar | 应用 → 客户端 Envoy → 服务端 Envoy → 应用 | 2 个代理 |
| Ambient(仅 L4) | 应用 → 源 ztunnel → 目的 ztunnel → 应用 | 2 个节点代理 |
| Ambient + waypoint | 应用 → ztunnel → waypoint → ztunnel → 应用 | 3 个代理 |
每跳代理都会带来解析、路由、TLS、队列和 CPU 调度成本。mTLS 握手可以靠连接复用摊薄,但 p99 对 CPU throttling 极其敏感:代理被限流时,排队延迟会直接反映到业务尾延迟。
官方性能基线
Istio 官方性能文档(1.24 基准,1 KB payload、mTLS、2 worker threads、1000 rps)给出:
| 组件 | CPU | 内存 |
|---|---|---|
| Sidecar Envoy | ~0.20 vCPU | ~60 MB |
| Waypoint Envoy | ~0.25 vCPU | ~60 MB |
| ztunnel | ~0.06 vCPU | ~12 MB |
这些数字只适合做数量级估算:
- Sidecar 成本是每 Pod,Pod 多、流量低时固定成本高。
- ztunnel 成本是每节点,与 Pod 密度无关。
- waypoint 成本是每副本,共享范围越大,单位服务成本越低,但爆炸半径越大。
- 内存强依赖配置规模(Listener/Cluster/Route 数量),不能只看基准值。
成本模型
Sidecar 成本 ≈ Σ(Pod 数 × 单代理 CPU/内存 × 单价) + 控制面 + 可观测性存储 |
示例(仅示意):
- 500 个 Pod,每 Pod 峰值 1000 rps:Sidecar 约
500 × 0.20 = 100 vCPU、30 GB内存。 - 同样负载在 20 个节点:ztunnel 约
20 × 0.06 = 1.2 vCPU、240 MB。 - 2 个 waypoint 副本:约
0.5 vCPU、120 MB。
但真实 TCO 还包括:为代理预留的节点碎片、控制面副本、etcd 压力、指标/日志/追踪存储、平台团队人力、升级窗口和故障风险。
容量规划清单
- 服务数、Endpoint 数、配置对象数。
- 每 Pod/每节点 RPS、连接数、并发请求数。
- 协议分布(HTTP/1.1、HTTP/2、gRPC、TCP)。
- 变更频率(HPA、滚动发布、批处理)。
- 代理 CPU limit 与 throttling;
concurrency要与 CPU 匹配。 - 单 Envoy 配置内存、istiod 堆内存、xDS 推送耗时。
- 节点 ulimit、conntrack、文件描述符、内核参数。
- 可观测性采样率和保留周期。
工程优化
- 给 Sidecar 设置合理 requests/limits,避免被业务挤占;CPU limit 过低会导致尾延迟抖动。
- 高并发场景调整
concurrency,不要完全依赖默认值。 - 开启
holdApplicationUntilProxyStarts,避免应用先于代理启动导致启动期请求失败:
metadata: |
- 对不需要经过网格的出站端口使用
traffic.sidecar.istio.io/excludeOutboundPorts排除;不要把业务端口排除。 - 大规模集群用
Sidecar和discoverySelectors控制配置规模。 - Ambient 下 ztunnel 随节点数增长,waypoint 随作用域和流量增长;waypoint 要按爆炸半径做 HPA/PDB。
- 接近 4 万 workload 时关注 1.31 的 WDS 重连消息大小问题,必要时调大
ISTIO_GPRC_MAXRECVMSGSIZE。 - 压测要测 p99、CPU throttling、连接复用和错误率,不要只测单跳 echo 的平均延迟。
可观测性落地
- 先统一指标、日志、追踪的采集标准,再谈告警
- 用 SLO 驱动告警,而不是对所有 5xx 都告警
- 区分
source和destination的指标,避免错误率重复计算 - 为入口网关、核心服务、控制面分别建看板
- 控制面要监控 istiod 的 xDS 推送、证书签发和队列积压
VM 与非 Kubernetes 工作负载
- VM 工作负载通过
WorkloadEntry/WorkloadGroup接入,证书和健康检查由 istio-agent 负责。 - VM 需要能访问 istiod(15012)和集群网络;跨网络时走 East-West Gateway。
- VM 的启动顺序、时钟同步、证书挂载和自动注册是主要故障源。
- 多集群/多网络的完整模型见 多集群与多网络。
常见反模式
- 用
EnvoyFilter改核心配置:低层逃生舱,升级容易失效,优先用 Telemetry、WasmPlugin、Gateway API Gateway使用hosts: ["*"]:任何 VirtualService 都能绑定,容易暴露意外域名- 没有默认路由:新版本一上线就自动接流量
- 同一命名空间混用 Sidecar 和 Ambient:行为难以预测
- 把
REGISTRY_ONLY当安全边界:绕过 Sidecar 的流量仍可出网 - 把
Sidecar当出站访问控制:它只限制配置范围,不阻断流量 - 指标标签不加控制:Prometheus 基数和成本失控
- 只配 mTLS 不配授权:有合法证书的客户端仍能访问所有服务
升级与故障学
1.31 升级注意事项
从 1.30 升到 1.31 时,至少检查以下变化:
| 变化 | 影响 | 动作 |
|---|---|---|
| WDS 重连消息变大 | 约 4 万 workload 可能超过 4MiB gRPC 限制,ztunnel 重连循环 | 调大 ISTIO_GPRC_MAXRECVMSGSIZE,观察 ResourceExhausted |
| 默认发送不健康 Endpoint | 后端异常时仍可能接流量 | 配置 OutlierDetection.minHealthPercent,或评估 PILOT_AUTO_SEND_UNHEALTHY_ENDPOINTS=false |
XDS api generator 要求控制面身份 |
非系统命名空间的自定义 MCP 消费者被拒绝 | 使用受支持的身份,或评估 ENABLE_XDS_API_GENERATOR_AUTH=false |
| Gateway API CRD 最低版本 | 低版本资源被静默过滤,TLS passthrough 可能失效 | 升级 CRD;istioctl analyze 会报 IST0176 |
PILOT_SPAWN_UPSTREAM_SPAN_FOR_GATEWAY 移除 |
无法再关闭网关上游独立 span | 调整追踪采样/后端容量 |
| 严格 Gateway 合并默认开启 | 跨命名空间 Istio Gateway 与托管 Gateway API 不再合并 | 检查多命名空间网关配置,必要时设置 PILOT_ENABLE_STRICT_GATEWAY_MERGING=false |
升级策略
- 控制面先行:先安装新 revision 的 istiod,旧 revision 继续服务存量 Sidecar。
- 数据面分批:按命名空间/工作负载切换
istio.io/rev并重建 Pod;Sidecar 升级必然伴随 Pod 重建。 - Ambient 分层:先 istiod,再 ztunnel DaemonSet,最后 waypoint;应用 Pod 通常无需重建,但要验证 HBONE、L4/L7 策略和 waypoint 路由。
- 版本偏差:遵循官方支持矩阵,通常控制面可以领先数据面一个小版本;不要让偏差长期存在。
- 回滚:保留旧 revision 和旧镜像;回滚时切回
istio.io/rev并重建 Pod。Ambient 要同时回滚 ztunnel/waypoint。 - 升级前:
istioctl x precheck、istioctl analyze -A、备份 CRD、确认 Gateway API CRD 版本、检查证书剩余寿命。 - 升级后:
proxy-status全部SYNCED,mTLS 比例不下降,错误率/P99 无回归,证书签发正常。
故障域
| 组件 | 故障影响 | 数据面是否继续 | 关键动作 |
|---|---|---|---|
| istiod | 新配置、注入、证书轮换停止 | 已下发配置继续转发 | 多副本、PDB、跨 AZ、证书 TTL 余量 |
| 注入 Webhook | 新 Pod 创建被拒绝(failurePolicy: Fail) |
存量 Pod 不受影响 | webhook 多副本、预检、变更窗口 |
| CA | 新证书签发失败 | 证书到期前继续 | 外部 CA HA、根证书备份、到期告警 |
| xDS | 配置 NACK/STALE | 旧配置继续 | proxy-status、analyze、配置回滚 |
| ztunnel | 节点上 Ambient Pod 连通性受损 | 该节点不继续 | DaemonSet 自愈、节点隔离、监控 |
| waypoint | 作用域内 L7 策略/路由失效 | 该作用域受影响 | HPA/PDB、按安全边界拆分、金丝雀 |
| CNI | 新 Pod 无重定向/启动失败 | 存量可能不受影响 | CNI 日志、repair、节点排空 |
| 网关 | 南北向/东西向入口中断 | 内部东西向可能不受影响 | 多副本、跨 AZ、容量与 PDB |
| DNS | 解析失败/延迟 | 依赖 DNS 的调用失败 | DNS 代理、CoreDNS、ServiceEntry 监控 |
故障排查顺序
- 定范围:单 Pod、单服务、单命名空间、单节点、单集群,还是全网格?
- 定路径:请求走 Sidecar、ztunnel 还是 waypoint?看 listener/route/cluster/endpoint。
- 定身份:mTLS 是否成功?证书是否有效?principal/trust domain 是什么?
- 定策略:PeerAuthentication、RequestAuthentication、AuthorizationPolicy 哪条命中?
- 定控制面:
proxy-status是否 STALE/NACK?istiod 是否在推送?证书是否在轮换? - 定数据面:CPU throttling、连接池、Endpoint 健康、DNS。
- 最后抓包:
tcpdump、ztunnel 日志、Hubble,验证“配置”和“实际流量”是否一致。
排障
常用命令
istioctl analyze -A |
Ambient 模式下 ztunnel 的配置、证书和连接状态用 istioctl ztunnel-config 系列命令查看(子命令以 istioctl ztunnel-config --help 为准);proxy-status 主要看 waypoint/Envoy。
注入失败
检查:
- 命名空间是否有
istio-injection=enabled或istio.io/rev - Pod 是否有
sidecar.istio.io/inject: "false" - 是否同时设置了
istio-injection和istio.io/rev - istiod 注入 Webhook 是否健康
- Pod 是否已经创建在注入标签生效之前
503 排查
先看响应码和 Envoy response flags:
UF:上游连接失败;若启用 Istio 认证,先查 mTLS 冲突UH:没有健康上游,检查 Endpoint、就绪探针、subset 标签UO:上游连接池/熔断溢出(circuit breaking)URX:上游重试次数超限NR:没有匹配路由,检查 VirtualService host、Gateway 绑定和端口
排查顺序:
istioctl proxy-config endpoint <pod>看上游是否存在istioctl proxy-config route <pod>看路由是否命中- 对比源 Sidecar 和目标 Sidecar 的配置
- 检查 NetworkPolicy、mTLS 模式和证书
- 必要时在 Pod 内抓包
证书与 mTLS 问题
PeerAuthentication切成STRICT后出现 503,通常是仍有明文客户端- 检查客户端是否注入 Sidecar
- 检查证书是否过期、istiod CA 是否正常
- 多集群场景检查信任域和根证书是否一致
- 用
istioctl proxy-config secret <pod>查看证书状态
配置不生效
istioctl analyze是否有警告proxy-status是否SYNCED- VirtualService 的
hosts是否与 Service 名称/命名空间匹配 - Gateway 的
hosts是否允许该域名 - subset 是否在 DestinationRule 中定义
- 是否被更具体的路由或 AuthorizationPolicy 覆盖
性能问题
- 对比注入前后的延迟和 CPU
- 检查 Sidecar 的
concurrency和资源限制 - 检查是否有大量 503/重试导致放大
- 检查 xDS 配置大小和推送频率
- 大规模集群评估改用 Ambient,减少每 Pod 代理开销
Ambient 排障
Ambient 的排障入口与 Sidecar 不同:
# ztunnel 视角:工作负载、服务、连接、证书 |
常见问题:
- L4 通、L7 策略不生效:目标没有 waypoint,或
use-waypoint没打对;确认waypoint-for与原始目标类型。 - 策略配置了但没执行:流量来自 Sidecar/Gateway/网格外,当前不会经过 waypoint;检查实际路径。
- Pod 没加入 Ambient:命名空间/Pod 的
dataplane-mode标签、CNI 就绪状态、Pod 是否在标签生效前创建。 - 节点上所有 Ambient Pod 异常:先看该节点 ztunnel 是否健康,再排 CNI/内核。
- mTLS 失败:看
ztunnel-config certificates的证书和身份,确认 trust domain 与策略 principal 一致。 - ingress 不走 waypoint:默认就不走;需要
ingress-use-waypoint=true且 istiod 开启ENABLE_INGRESS_WAYPOINT_ROUTING。
最佳实践清单
- 使用 revision 升级,istiod 至少 2 副本
- 切换 revision 时先移除
istio-injection - 每个服务配置默认路由
- 新增 subset 使用 make-before-break
- Gateway
hosts收紧,不使用* - mTLS 从
PERMISSIVE迁移到STRICT - 默认拒绝授权,按服务放行
- 对外接口启用 JWT 或外部授权
- 出口流量走 Egress Gateway + NetworkPolicy
- 用
Sidecar限制配置可见范围,但不把它当访问控制 - 控制指标基数,配置日志轮转和采样
- 所有配置纳入 GitOps,CI 执行
istioctl analyze - 避免 EnvoyFilter,优先使用官方扩展点
- 同一命名空间不要混用 Sidecar 和 Ambient
- 定期演练证书轮换、控制面故障和网关扩容
- 1.31 升级前检查 WDS 消息大小、不健康 Endpoint 默认行为、Gateway API CRD 版本
- Ambient waypoint 按安全边界拆分,配置 HPA/PDB,并验证 Sidecar/Gateway 流量路径
- 多集群校验 trust domain、根证书和同名命名空间合并
- 用 source/destination 两种口径和 response_flags 建 SLO 看板
- 性能基线同时测量 P99、CPU throttling 和连接复用
- 证书根轮换、CA 故障、istiod 全挂都有演练记录
附录
命令速查
# 安装与升级 |
API 版本
| 资源 | API |
|---|---|
| VirtualService、DestinationRule、Gateway、ServiceEntry、Sidecar、WorkloadEntry | networking.istio.io/v1 |
| WorkloadGroup | networking.istio.io/v1 |
| PeerAuthentication、RequestAuthentication、AuthorizationPolicy | security.istio.io/v1 |
| Telemetry | telemetry.istio.io/v1 |
| WasmPlugin | extensions.istio.io/v1alpha1 |
| EnvoyFilter | networking.istio.io/v1alpha3 |
| Gateway、HTTPRoute、GRPCRoute | gateway.networking.k8s.io/v1 |
安装后可用 kubectl api-resources | grep istio 核对当前集群实际支持的版本。