土法炼钢兴趣小组的算法知识备份

【Istio 控制面】控制面全景:从 CRD 到 xDS 的翻译与推送内核

文章导航

分类入口
networkkubernetes
标签入口
#istio#xds#istiod#control-plane#service-mesh#pilot#ambient

目录

站内已经有三块内容离「Istio 控制面」很近,却都不回答同一个问题。Envoy 数据面系列 09–11 篇 把 xDS 消费侧讲透:资源树怎么按名字引用、ACK/NACK 是什么协议承诺、warming 为什么让「已推送」不等于「已生效」。但那三篇的前提永远是「假设某个管理服务器已经给出了合法的 LDS/RDS/CDS/EDS」——管理服务器内部发生了什么,不在 Envoy 系列的范围里。Service Mesh 讲清了 sidecar 税与 Ambient 的代价地图,但落点是「要不要上 Mesh」的选型判断,不是「一次 VirtualService apply 之后控制面做了什么」。Gateway API 定义了南北向流量的资源模型与角色分层,但没有回答这些资源如何被某个具体的网格控制面消费、翻译、推送。

三块内容叠在一起,读者能看到「代理侧怎么消费」「要不要上代理」「资源该长什么样」,唯独看不到中间那台真正做事的机器:istiod 如何把一份 CRD 或 Gateway API 资源,编译成某一个具体代理上的一份 xDS 资源图,推给谁,推送本身是否成功,这件事和 Envoy 端的 warming 状态机是两回事。 本篇是系列第一篇,只做三件事:钉住这个缺口的精确边界、给出后续 15 篇共用的五条坐标系,以及明确划出本系列不会展开的范围。

本文是「Istio / 网格控制面内核」系列第 1 篇(共 16 篇)。→ 系列目录

下接 第 2 篇 · istiod 进程模型

版本锚定:Istio 1.30.3istio/istio tag);架构叙述以该 tag 下 architecture/networking/pilot.mdpilot/pkg/xds/pkg/model/proxy.go 为准。数据面消费侧机制外链 Envoy v1.39.0 系列,不在本系列重写。


一、缺口:三份已有内容分别停在哪一层

把四份内容按「回答什么问题」摆在一起,缺口的形状就很清楚:

内容 回答的问题 明确不回答
Envoy 09–11 给定合法 xDS 响应,Envoy 怎么消费、ACK/NACK、warming 响应是谁生成的、生成依据是什么
architecture/76 sidecar/Ambient 的部署代价与选型权衡 控制面内部的翻译与推送机制
k8s-network/18 Gateway API 资源模型与角色分层 某个具体控制面(Istio)如何消费这些资源
本系列 istiod 如何把配置编译成某代理的资源图,推给谁,何时算失败 Envoy 侧消费细节(外链)、Mesh 税叙事重写、CRD 教程

这张表本身就是本系列的立项理由:读者已经具备「消费侧怎么工作」「值不值得上」「资源长什么样」三种视角,但没有「生产侧怎么工作」的视角。三者合起来才是一次配置变更的完整生命周期——从 kubectl apply 到某个 Pod 里的 Envoy 真的按新规则转发流量。

一次配置变更的完整生命周期:三块已有内容与本系列的缺口位置

二、谱系:xDS 从协议变成控制面产品

xDS 最初只是 Envoy 用来描述「动态配置」的一组 gRPC/REST 接口;它变成今天这种带调度、去抖、多客户端类型的控制面产品,经过了三次可考证的分叉。

第一次分叉:从「多流」到「单流可排序」。 Istio Pilot 早期(istio/pilot 仓库,2017 年前后)为 LDS/CDS/EDS 各开一条独立 gRPC 流。2018 年 4 月的 istio/istio#4670「Switching to ADS」(作者 costinm)把这一套改成了单条 StreamAggregatedResources,提交说明直接写明动机:EDS 不支持按 cluster 批量请求,多流模式下会为每个 cluster 各开一条 Cluster*Endpoints 流,「不 scale」。这次改动是 Istio 主动把自己的生产侧收敛到 Envoy 后来在协议文档里正式定义的 ADS 语义上——这是一条可以在提交记录里直接核对的分叉点,不是后验的历史叙事。

第二次分叉:从「五个微服务」到「一个进程」。 Istio 早期把服务发现(Pilot)、配置校验(Galley)、证书签发(Citadel)、注入 webhook 拆成独立部署。Istio 1.5(2020)的官方博客《Introducing istiod: simplifying the control plane》给出的理由很直接:这些组件之间没有独立伸缩或独立团队交付的收益,拆分只带来了运维复杂度,于是合并成单一二进制 istiod。这次合并不改变 xDS 协议本身,但决定了本系列第 2 篇要讲的进程边界。

第三次分叉:从「通用 xDS 类型」退回「领域特化协议」。 Ambient 模式给 ztunnel 设计配置协议时,architecture/ambient/ztunnel.md(1.30.3)记录了一个反直觉的决定:继续用 xDS 传输协议(gRPC 双向流、ACK/NACK 语义),但不用 Listener/Cluster 这些通用资源类型,而是自定义了 AddressAuthorization 两种精简类型。文档给出的理由是实测:用 Envoy 通用类型表达一条 mTLS 语义要几十行 Protobuf,而 ztunnel 用带 Istio 语义的字段(例如 ExpectedTLSIdentity)能把同样的信息压缩到十分之一体积与 CPU 开销。这是「协议要不要为特定客户端做领域特化」的一次工程判断,第 3 篇会展开。

三次分叉串起来是同一条主线:「用什么协议传」和「协议里装什么类型」是两个可以独立演化的维度——ADS 解决的是传输层的排序问题,istiod 合并解决的是运维复杂度问题,ztunnel 的自定义类型解决的是资源效率问题。理解这条主线,才能理解为什么本系列要单独用一篇(第 3 篇)讲「谁在订阅」,而不是默认所有代理都在消费同一套 LDS/RDS/CDS/EDS。


三、五条坐标系

后续 15 篇都会落到下面某一条轴上,本篇只钉名字。

3.1 资源来源轴

K8s Service/EndpointSliceVirtualService/DestinationRule、Gateway API HTTPRoutePeerAuthentication/AuthorizationPolicy 等输入,先要变成 istiod 内部统一的 model.Servicemodel.PushContext 等结构,才谈得上生成任何 xDS 资源。输入格式的多样性在这一层被吃掉——第 2 篇(Config Ingestion)与第 5–9 篇的翻译系列都落在这条轴上。

3.2 订阅身份轴

一个 Connection 连上来,istiod 先解析它的节点 ID(type~ip~id~domain 四段式)和 NodeMetadata,得到一个 model.Proxy,其 Type 字段是 SidecarProxyRouterWaypointZtunnelAgentgateway 之一(pkg/model/proxy.go,1.30.3)。不同类型订阅的资源集合、走的 Generator 都不同——第 3 篇专门讲这条轴。

3.3 推送图轴

一次配置变更从 K8s watch 事件开始,经过 debounce 合并、PushContext 重算、PushQueue 排队,最后由某个 push worker 调用 pushXds 生成并发送 DiscoveryResponse这条链路的每一段都可能是延迟或丢推送的来源——第 4 篇专门画这张图。

3.4 一致性 / warming 责任轴

istiod 侧的 ConfigUpdate 只表示「收到了变更」;AdsPushAll 只表示「已经尝试推送」;Envoy 侧的 ACK 只表示「协议校验通过并打算应用」(Envoy 第 10 篇);真正决定流量是否已切换的是 Envoy 的 warming 状态机(Envoy 第 11 篇)。「控制面已推送」「代理已 ACK」「流量已生效」是三个独立事件,排障时把它们混为一谈是生产事故复盘里的高频误判——第 4、10–11、15 篇都会回到这条轴。

3.5 作用域轴

SidecarTelemetryEnvoyFilter 这些资源不生成新的 xDS 类型,而是收窄或改写「某个代理该看到哪些资源」。ProxyNeedsPush 之类的过滤逻辑决定了一次 Service 变化到底要不要推给某个具体代理——作用域算错,代价是要么推送风暴,要么该收到更新的代理没收到。第 9 篇专门展开。

flowchart TD
  subgraph axes ["Five coordinate axes"]
    A1["Source axis<br/>CRD/K8s objects to model"]
    A2["Identity axis<br/>sidecar/ztunnel/waypoint/gateway"]
    A3["Push graph axis<br/>watch to debounce to ADS"]
    A4["Consistency axis<br/>pushed vs ACKed vs serving"]
    A5["Scope axis<br/>Sidecar/Telemetry/EnvoyFilter"]
  end
  A1 --> A3
  A2 --> A3
  A3 --> A4
  A2 --> A5
  A5 --> A3

四、16 篇地图与本篇边界

flowchart LR
  p1["01 Overview"] --> p2["02 istiod Process"]
  p2 --> p3["03 Proxy Identity"]
  p3 --> p4["04 Push Graph"]
  p4 --> p5["05-09 Translation"]
  p5 --> p10["10-12 Scale & Ownership"]
  p3 --> p13["13-14 Ambient & Linkerd"]
  p10 --> p15["15-16 Troubleshoot & Selection"]
  p13 --> p15
部分 篇目 一句话
坐标与推送图 01–04 缺口、istiod 进程、代理身份、推送图
翻译层 05–09 Service/Endpoint、VirtualService、DestinationRule、Authn/Authz、Sidecar/EnvoyFilter
规模与 Ambient 10–14 生产侧 SotW/Delta、NACK/warming 责任、多集群、Ambient、Linkerd 对照
收束 15–16 排障对齐、选型与开放问题

全系列 01–16 已发布。本篇之后按 02 → 03 → 04 补齐坐标系;翻译层可直达第 5 篇(Service/Endpoint → CDS/EDS),推送经济学可直达第 10 篇(生产侧 SotW/Delta);收束见第 15–16 篇。


五、与站内三份内容的分工

站内内容 负责 本系列不重复
Envoy 系列 消费侧协议、warming 状态机、排障与选型 Filter/HCM/连接池内核;Hot restart
architecture/76 sidecar 税、Ambient 代价地图、选型判断 未实测延迟排行、云成本报价
k8s-network/18 Gateway API 资源模型、角色分层、GAMMA CRD 字段级教程
本系列 istiod 翻译、订阅身份、推送图、一致性责任边界 上述三者已覆盖的内容

读法:只要「建立 Mesh 坐标系」→ architecture/76 足够;要「代理侧卡在哪」→ Envoy 系列;要「控制面推了什么、推给谁、失败算谁的」→ 本系列。


六、明确不写什么

以下内容读者可能期待出现在「Istio 控制面」标题下,本系列刻意不展开,原因写清楚:


七、参考资料

官方文档 / 规范(A)

源码 / 提交记录(A)

官方博客(B)

站内对照

实验台账


八、小结

  1. 缺口是精确的:Envoy 系列管消费侧、architecture/76 管选型、k8s-network/18 管资源模型,三者都不管「istiod 内部如何翻译与推送」——这正是本系列的领地。
  2. 三次谱系分叉(ADS 化、istiod 合并、ztunnel 自定义协议)说明 xDS 的「传输协议」与「资源类型」是两个可以独立演化的维度,后续篇目会反复用到这个区分。
  3. 五条坐标系(来源、身份、推送图、一致性、作用域)是全系列的共用语言,第 2–4 篇立刻会用到前三条。
  4. 明确的不写清单,避免本系列膨胀成 Istio 全功能手册。

系列目录 · 下一篇:istiod 进程模型

同主题继续阅读

把当前热点继续串成多页阅读,而不是停在单篇消费。

2026-08-11 · network / kubernetes

Istio / 网格控制面内核:从 CRD 到 xDS

补齐 Envoy 数据面 xDS 消费侧与 Mesh 选型叙事之间的控制面内核:istiod 推送图、CRD/HTTPRoute 翻译、Ambient 多客户端、NACK/warming 责任与排障对齐。


By .