第 21 章 服务网格 Istio:和 K8s 原生的边界在哪

墨:老哥,K8s 的 Service 已经做了负载均衡和稳定寻址(第 9 章),那**服务网格(Istio/Linkerd)**又是干嘛的?这不重复吗?先别急着记概念,先想:K8s 原生处理”服务流量”,到哪一步就不够了?


21.1 K8s 原生流量治理的”天花板”

回忆第 9 章:K8s Service 给你集群内 L4 负载均衡 + 稳定 VIP,Ingress 给你集群外 L7 路由(按域名/路径)。听起来够?但生产要的流量治理能力,K8s 原生够不到:

  • 按百分比灰度(金丝雀):“把 5% 流量导到新版本”——Service 是”随机均分”,Ingress 是按规则路由,都不原生支持”按权重切流”;
  • 熔断 / 限流 / 重试:某后端慢了,调用方该熔断还是重试?K8s 不管,得应用自己写(每个语言各写一套);
  • mTLS(服务间双向加密):Pod 间流量默认明文(同网络内可被嗅探),K8s 不自动加密服务间通信;
  • 细粒度流量观测:每个服务间的调用延迟、错误率、调用图——K8s 原生没有(第 17 章 traces 要你自己接);
  • 故障注入 / 流量镜像:测试时”让 10% 请求返回 500”或”复制流量到影子服务”——K8s 原生无。

墨:这些问题有个共同特征,你发现没? 它们都是**“服务间通信的治理逻辑”,且和具体业务无关**——熔断、重试、mTLS、指标,任何微服务都要,但每个服务自己写一遍太蠢。这就是服务网格要填的坑:把”服务间通信的横切关注点”从应用里抽出来,下沉到基础设施。

核心洞察:服务网格 = 把”通信治理”从应用代码下沉到”独立的数据面代理”。 正如 K8s 把”运行调度”从人肉下沉到控制面——同一类”横切关注点下沉”的思路(和 sidecar、CNI、追踪同构)。


21.2 sidecar:网格怎么”插”进你的 Pod

墨:网格怎么截获你的服务流量,又不改你代码? 靠第 8.8 讲的 sidecar——给每个 Pod 注入一个 Envoy 代理容器(Istio 用 Envoy),它和你的业务容器同 Pod、共享网络(localhost)。

机制:

  • 你的业务容器发往 orders:8080 的流量,被 iptables 规则(由 Istio 的 init 容器/原生 sidecar 设置)重定向到同 Pod 的 Envoy(localhost:15001);
  • Envoy 按网格规则(加权路由、重试、mTLS)决定真发往哪个后端,并加密(mTLS)、记录指标;
  • 对端 Pod 的 Envoy 接收、解密、转给对端业务容器。

墨:所以业务代码完全无感? 对。你的代码还是 http://orders:8080,不知道中间过了 Envoy。这就是 sidecar 的价值——治理逻辑在 Pod 内的代理里,应用零改动。这正解释了第 8.8 为什么 Istio 用 Mutating Admission Webhook 注入 sidecar(第 14.3 的答案):在 Pod 创建请求进 etcd 前,自动加 Envoy 容器 + 重定向规则。

演化/代价: sidecar 每 Pod 多一个 Envoy,占资源(每 Envoy ~100MB 内存)、启动慢(第 8.8 的启动顺序问题)、运维复杂。所以后来有 ambient mesh(Istio 的”无 sidecar”模式):把代理下沉到节点级(每个节点一个 agent),不再每 Pod 一个 sidecar,减资源。又是”每实例 vs 每节点”的权衡(和第 8.7 DaemonSet 同思路)——sidecar 隔离好但重,节点级轻但共享。


21.3 控制面(Istiod)与数据面(Envoy)

Istio 架构:

  • 数据面:各 Pod 的 Envoy 代理,真正转发/加密/记录流量;
  • 控制面(Istiod):把你的流量规则(VirtualService、DestinationRule)翻译成 Envoy 配置,下发给各 Envoy;并管证书(mTLS 的 CA)。

墨:这像不像 K8s 自己? 太像了。Istiod 是”网格的 API Server + 控制器”,Envoy 是”网格的 kubelet/数据面”。你用 YAML 声明”流量规则”(声明式,第 3 章),Istiod 调和到 Envoy(控制循环),Envoy 执行。服务网格复刻了 K8s 的声明式+控制循环范式——因为它解决的是同类问题(“期望的流量行为” vs “实际流量”)。这是 K8s 范式向外辐射的证据:它的设计哲学太好用,连上层系统都照抄。


21.4 网格能做什么:四个招牌能力

21.4.1 流量管理(金丝雀/蓝绿/镜像)

VirtualService 声明:“90% 去 v1,10% 去 v2”(金丝雀)、“按 header 路由”(如 x-canary: true 去 v2)、“镜像 100% 流量到影子服务但不影响真实响应”。这些是应用层 L7 精细控制,K8s Service/Ingress 原生做不了(Ingress 只按域名/路径,不懂”权重/header”)。

21.4.2 弹性(重试/超时/熔断)

DestinationRule 设:“调用超时 2s、重试 2 次、连续 5 次错就熔断该实例”。这些以前要写在应用里(Go 的 hystrix/ resilience 库),现在下沉到 Envoy,所有语言的服务统一获得,且不用改代码。

21.4.3 mTLS(服务间加密)

Istiod 作 CA,给每个服务发证书,Envoy 间自动 mTLS——服务间流量默认加密,嗅探者拿不到明文。这补了 K8s 网络默认明文(同 CNI 内 Pod 间流量不加密)的洞。和 NetworkPolicy(第 9.7/13.6)互补:NetworkPolicy 管”能不能通”,mTLS 管”通了是不是加密+鉴权对方身份”。

21.4.4 可观测性

Envoy 自动产生每跳的指标(RED)、访问日志、trace span(第 17.4)——不用改应用代码就获得调用链追踪。这是网格”白送可观测”的红利。


21.5 边界:网格 vs K8s 原生,谁管什么

墨:那有了 Istio,K8s 的 Service 还要吗?Ingress 还要吗? 都要,且分工清晰:

能力K8s 原生服务网格
集群内寻址/L4 LBService(VIP+iptables/ipvs)不替代,网格在 Service 之上做 L7
集群外 L7 路由Ingress/Gateway API网格的 VirtualService 可做更细,但入口常仍用 Gateway
按权重/header 切流无VirtualService
重试/超时/熔断无(应用自己)Envoy
mTLS 服务间无(明文)Envoy mTLS
调用链追踪需应用埋点Envoy 自动

关键边界:K8s 管”服务在哪、基础寻址”,网格管”服务间流量怎么治理”。网格建立在 Service 之上——Envoy 仍把流量发到 Service 的 VIP/端点,只是中间加了 L7 治理。 它不是替代 K8s 网络,是叠加在 K8s 网络之上的 L7 增强层。

墨:那小团队要上 Istio 吗? 未必。网格有重量(sidecar 资源、运维复杂度、调试难)。如果你只要”稳定寻址+简单 Ingress”,K8s 原生够。网格适合”大量微服务、且要统一治理流量/安全/可观测”的团队——它用”复杂度”换”统一的、语言无关的治理能力”。又是”能力 vs 复杂度”的权衡(和 Swarm 简单但弱、K8s 复杂但强同源,第 2.5.3)。


21.6 一个容易混的点:网格和 API Gateway

墨:网格(Istio)和 API Gateway(如 Kong、APISIX)啥区别? 都在”流量”上,但位置不同:

  • API Gateway:在集群边界,管”外部用户→集群内”的流量(认证、限流、协议转换、计费);
  • 服务网格:在集群内部,管”服务→服务”的流量(mTLS、熔断、内部观测)。

一个在企业架构里常是双层:外部流量先过 Gateway(边界治理),进集群后过 Mesh(内部治理)。Gateway 管”门口”,Mesh 管”屋内”。别以为上了 Mesh 就不用 Gateway(或反之)。


21.7 为什么网格用 sidecar 而不是改内核/改 Service

墨:网格要截流量,为啥不用”改 K8s Service 的转发逻辑”,非要每 Pod 塞 Envoy? 因为 sidecar 是”对应用零侵入”的最优解:

  • 改 Service(kube-proxy)耦合所有服务、且 Service 是 L4,做不了 L7(权重/header);
  • 改内核(eBPF 做网格,如 Cilium mesh)是另一路线(第 9.4 的 eBPF 思路),能去 sidecar,但要求新内核且生态较新;
  • sidecar(Envoy)在用户态、独立进程、语言无关、易迭代——用”每 Pod 一个代理”换”应用零改 + 能力独立演进”。

这又回到第 8 章的”Pod 作为包裹”——sidecar 能塞进 Pod,正是因为 Pod 是”一组协作容器”的抽象(第 8.1)。没有 Pod 这个抽象,sidecar 模式都没地方挂。 K8s 的底层抽象(Pod)默默支撑了上层无数能力(sidecar、日志采集、网格),这是好抽象”复利”的例子。


21.8 本章演化线小结

  • K8s 原生流量治理天花板:无权重切流/熔断/重试/mTLS/细观测;
  • 服务网格把”通信治理”下沉到 sidecar(Envoy),应用零改(第 8.8 webhook 注入);
  • Istiod(控制面)+ Envoy(数据面)复刻 K8s 声明式+控制循环范式;
  • 四能力:流量管理(金丝雀/权重)、弹性(重试/熔断)、mTLS、可观测;
  • 边界:K8s 管寻址/L4,网格管 L7 治理,叠加非替代;Gateway 管边界、Mesh 管内部;
  • ambient mesh 去 sidecar 走向节点级(每实例 vs 每节点权衡);好抽象(Pod)支撑上层能力。

21.9 本章思考题

🔧 思考题 1

你说 Istio sidecar 让应用零改。但某天你发现”服务 A 调 B 变慢了”,排障时流量经过 A 的 Envoy → Service VIP → B 的 Envoy。请描述这条链上你能用网格的哪些信号定位”慢在哪一段”,对比不用网格时你怎么查。

【参考答案】 有网格:Envoy 自动产出每个 hop 的 RED 指标 + trace span。你能看:(a) A→A.Envoy 的本地代理处理耗时;(b) A.Envoy→B.Envoy 的网络+处理耗时(含 mTLS 握手);(c) B.Envoy→B 应用 的入向耗时。Trace 拼出调用链,一眼看出慢在”网络段”还是”B 应用本身”。且 Envoy 访问日志有每请求明细(哪段超时/重试)。不用网格:你只能看 A 应用日志(“调 B 超时”)和 B 应用日志(“收到慢”),但中间网络段、iptables 转发、Service 后端选择全黑——得自己 tcpdump、查 kube-proxy 规则、查 Service Endpoint,极费力且跨团队(网络/平台/应用)扯皮。网格的价值正在于”把跨服务的黑盒变成可观测的调用链”,排障从”各看各日志猜”变”看一条 trace”。这题考你理解网格的”可观测红利”是它最易被低估的价值(很多人只盯流量管理)。

🔧 思考题 2

你们只有 5 个微服务,团队 3 人。有人说”上 Istio 显得专业”。你会建议上吗?从”能力 vs 复杂度”权衡给出判断,并指出什么信号出现才该上。

【参考答案】 不建议。3 人管 5 服务,上 Istio 的复杂度(sidecar 资源、Istiod 运维、mTLS 证书、排障多一层、版本升级)远超收益——你要的”稳定寻址+L7 路由”用 K8s Service + Ingress/Gateway API 就够(第 9.6/21.5)。网格的招牌能力(权重金丝雀/mTLS/统一熔断/调用链)在 5 服务时要么用不上、要么用更简单方案(如 Ingress 权重、应用内简单 retry)能凑。该上的信号:(1) 服务数到几十+,且多语言(Go/Java/Python 混),统一治理(mTLS/熔断)靠应用各自写不现实;(2) 强合规要求服务间加密(mTLS 刚需);(3) 频繁灰度发布需要权重/header 路由,Ingress 不够;(4) 排障痛点:服务间调用黑盒导致事故定位慢,需调用链。出现这些,网格的”复杂度税”才值。结论:网格是”规模/多语言/强治理”的解药,不是”专业感”的装饰。小团队先 K8s 原生,长大再上网格——和第 2.5.3 “Swarm 简单 vs K8s 复杂”的同构取舍。

🔧 思考题 3

ambient mesh(无 sidecar)把 Envoy 下沉到节点级(每节点一个 ztunnel/waypoint)。这解决了 sidecar 的什么问题、又引入什么新问题?对比”每 Pod sidecar”和”每节点代理”两种部署的权衡。

【参考答案】 解决:sidecar 每 Pod 一个 Envoy,资源开销大(N 个 Pod = N 份 Envoy 内存/CPU)、Pod 启动慢(要先起 Envoy)、升级 Envoy 要重建 Pod。ambient 节点级代理,资源按节点摊薄(一台机器上所有 Pod 共享少数代理)、Pod 启动快(不注入 sidecar)、代理升级不影响 Pod 生命周期。引入新问题:(1) 隔离性下降:同节点 Pod 共享代理,一个 Pod 的流量策略错误/代理故障可能影响同节点其他 Pod(sidecar 是强隔离);(2) 多租户安全:节点级代理要正确隔离不同 Pod 的证书/流量,实现更复杂;(3) 性能:流量可能多一跳(过节点代理),延迟略增。权衡同第 8.7 DaemonSet vs Deployment、第 21.2 的”每实例 vs 每节点”:sidecar=隔离好但重,节点级=轻但共享。ambient 是”为降资源牺牲一点隔离”的取舍,适合资源敏感/大规模场景。这题考你对”部署粒度”权衡的通用判断——任何”每 X 一个组件”的选择,都是隔离性 vs 资源/复杂度的交易。

🔧 思考题 4(进阶)

服务网格(sidecar 模式)和 K8s 的”把通信治理下沉”思路,与第 14 章”用 CRD/Operator 扩展”是什么关系?如果把 Istio 看成”K8s 的一个扩展”,它用了本书讲的哪些扩展口子?这说明 K8s 的平台化有多成功?

【参考答案】 Istio 是 K8s 扩展能力的典范展示。它用的口子:(1) Mutating Admission Webhook(第 4.5/14.4):注入 sidecar + iptables 重定向规则(第 21.2/14.3);(2) CRD(第 14.2):VirtualService/DestinationRule/Gateway 都是 CRD,Istiod 是操作这些 CR 的 Operator(第 14.3);(3) CNI/网络:依赖 K8s 网络模型(第 9 章)在其上叠加;(4) RBAC/SA:网格组件用 K8s 身份(第 4/13)。也就是说,Istio 没改 K8s 一行核心代码,纯用”webhook + CRD + Operator”三个扩展口子就实现了完整的服务网格——且复刻了 K8s 自己的声明式+控制循环范式(21.3)。这说明 K8s 平台化(第 14.7)极其成功:它的扩展机制足够表达”一个复杂的上层系统”。如果 K8s 没开放这些口子,Istio 要么得 fork K8s(不可能),要么做得极丑陋。Istio 的存在本身,就是”把造系统的机制交给用户”这条哲学(18.2/14.7)的最佳证据。你做平台时也该以此为目标:能让生态用你的扩展口子长出 Istio 级别的系统。


21.10 小结

  • K8s 原生流量治理天花板:无权重切流/熔断/重试/mTLS/细观测;
  • 服务网格把”通信治理”下沉 sidecar(Envoy),应用零改(webhook 注入);
  • Istiod+Envoy 复刻 K8s 声明式+控制循环范式(好范式向外辐射);
  • 四能力:流量管理(金丝雀/权重)、弹性(重试/熔断)、mTLS、可观测;
  • 边界:K8s 管寻址/L4,网格管 L7 治理,叠加非替代;Gateway 管边界、Mesh 管内部;
  • ambient 去 sidecar 走向节点级(每实例 vs 每节点);Istio 是 K8s 扩展口子的典范。

下一章讲 GitOps——把”集群状态存在 Git 里、靠声明驱动”这件事做到极致。它和 K8s 的控制循环是同构的,你看了会说”哦,原来 Git 就是另一个 etcd”。