Istio 源码剖析:课程大纲 原创
Istio 难,不难在概念,难在你在配置文件里写下的一个
host,最后变成了 Envoy 里哪一段 JSON。中间这层翻译没有文档,只有代码。这门课程只做一件事:把这段翻译逐行拆开。从架构讲清它在哪、从源码讲透它怎么做、最后自己写一个能跑起来的 xDS 服务端,把"看过"变成"做过"。
一、为什么要写这门课程
关于 Istio 的中文资料,大致分两类:
一类讲怎么用——安装、VirtualService 怎么写、mTLS 怎么开。这类资料够用,但一旦配置"没生效",就读不下去了,因为你不知道它为什么应该生效。
另一类讲架构图——控制面、数据面、xDS、Pilot(以及早就并进 istiod 的 Citadel、Galley)几个方块加箭头。这类资料看完能画出图,但仍然回答不了三个最常问的问题:
- 我改了一个
VirtualService,为什么不是立刻生效?中间那段延迟在干什么? - 同样的配置,A 命名空间写了就生效,B 写的没反应,差异在哪一层?
- 一万个 Pod 的场景下,istiod 凭什么不炸?它省掉了哪些计算?
这三个问题的答案都在源码里,而且都在特定的几个函数里。找到那几个函数,Istio 就透明了。
这门课程的目标:读完能自己回答这三个问题,能自己写一个 xDS 控制面(最后一部分就是动手写),并且能把 Istio 里的几个设计(增量缓存、推送去抖、按需生成、声明式控制器运行时)拿来改造自己手上的系统。
二、写给谁看
| 读者 | 你会得到 |
|---|---|
| 正在用 Istio、被"配置不生效"折磨的 SRE / 平台工程师 | 一套从配置到 Envoy 的完整链路,排障时知道该看哪个 /debug 接口 |
| 想读源码但被几十万行劝退的后端 / 云原生开发 | 一条有顺序的阅读路线,每篇一个可验证的小目标 |
| 准备二次开发或给 Istio 提 PR 的人 | 每个模块的入口函数、依赖边界、改动会波及谁 |
| 想做自己的 xDS 控制面 / 服务网格 / 网关的人 | 最后一篇从零手写一个能连上的 xDS 服务端,不是伪代码 |
只被 istioctl proxy-config 的输出折磨、不打算读 Istio 源码的人 | 第 15~19 篇这条 Envoy 侧短路线,看懂每个字段是从哪一步来的 |
| 技术决策者 | 判断 Istio 的成本到底在哪、什么规模该用、什么时候不该用 |
前置要求:会 Go、知道 Kubernetes 的 Informer/CRD。Envoy 侧不用提前准备——第 15 篇《Envoy 基础》从"一个 TCP 连接进来怎么走"讲起,把 Listener/FilterChain/Route/Cluster/Endpoint 摆成一张图。也不要求读过 Istio 源码。
三、这门课程怎么讲
每篇都把三样东西叠起来讲:图讲逻辑(这条路怎么走、在哪分岔)、源码作证据(哪几个函数决定了行为)、文字做翻译(这段代码用人话是什么,换个写法会怎样)。三者交替推进,不写成"图一段、码一段、注一段"的拼盘。
- 每篇只回答一个能验证的问题,不写"XX 概述"。
- 源码只贴决定行为的那几行,其余用
// ...带过;每段代码后面都有"人话翻译"和一个反例。 - 每篇结尾给一条能自己跑的命令(
istioctl、curl /config_dump、func-e run),结论当场可验。 - 版本差异、没验证过的地方直接标出来,不假装跨版本通用。
四、版本基线:只认 tag,不认行号
源码分析类文章最大的坑是"半年后行号全变了"。本课程的处理方式:
- 基线版本:
istio/istio1.31.x(写作时最新稳定版 1.31.4,主干开发版已到 1.33)。文中的行为以 1.31 为准,与老版本的差异会单独标注。 - 定位方式用函数名,不用行号。例如不说"第 605 行",而说"
pilot/pkg/xds/discovery.go的debounce()"。函数名比行号稳定得多。 - 关键路径给出文件全路径,可以直接
grep -rn "func xxx"找到。 - 涉及 Ambient 的篇章会同时引用
istio/ztunnel(Rust 实现),因为它不在主仓库里;实践篇会引用envoyproxy/go-control-plane,因为手写服务端绕不开它。
复现环境建议:
git clone --depth 1 -b 1.31.4 https://github.com/istio/istio.git
cd istio && git log -1 --oneline # 确认基线五、先给一张源码地图
Istio 主仓库里,真正需要读的目录其实只有这几个(其余 tests/、samples/、prow/ 可以先忽略):
| 目录 | 职责 | 读它的理由 |
|---|---|---|
pilot/cmd/pilot-discovery | istiod 主进程入口 | 一切从这里开始 |
pilot/pkg/bootstrap | 依赖装配:CA、xDS、webhook、控制器全部在这里接线 | 想知道"谁依赖谁",看这个文件就够 |
pilot/pkg/model | 内部数据模型 + PushContext 快照 | 全仓库核心,配置翻译的中间层 |
pilot/pkg/serviceregistry | K8s / ServiceEntry / 内存注册中心抽象 | Service、Endpoint 从哪来 |
pilot/pkg/xds | xDS 服务端、推送队列、缓存 | 推送链路的主干 |
pilot/pkg/networking/core | Cluster/Listener/Route 生成器 | 配置最终长成什么样 |
pilot/pkg/networking/grpcgen | Proxyless gRPC 的 xDS 生成 | 不看 sidecar 也能用 Istio(附录 A1,低优先级) |
pilot/pkg/security | 认证/授权策略翻译成 Envoy filter | mTLS、JWT、RBAC 落地处 |
pkg/config | CRD 定义、校验、转换、kind 注册 | 你写的 YAML 长什么样由它决定 |
pkg/kube/krt | 自研声明式控制器运行时 | 理解现代 Istio 控制器的钥匙 |
pkg/kube/inject | sidecar 注入 webhook + 模板 | Pod 怎么被"改造" |
pkg/istio-agent | pilot-agent:数据面侧的小管家 | 证书、bootstrap、xDS 代理 |
security/pkg | CA、SDS 服务端、证书签发 | 身份体系的实现 |
cni/pkg | istio-cni 与流量重定向 | 没有特权时的流量劫持 |
pkg/workloadapi | Ambient 的 WDS 协议(protobuf) | 新架构的数据契约 |
一句话记忆:config 进来,model 加工,networking 生成,xds 送出,istio-agent 接收,Envoy 执行。最后一部分会把这条链路反着走一遍:以 Envoy 为起点,把它要的东西亲手造出来。
六、大纲:导论 + 七部分 + 一个实践,共 32 篇(00~31)
第 0 篇 · 导论
00. Istio 到底是什么:三个二进制、两类配置、一条链路
不讲概念,直接 kubectl get pod -n istio-system 看到的东西逐个拆:istiod、istio-cni-node、istio-proxy(以及 Ambient 下的 ztunnel、waypoint)。区分控制面/数据面、SotW/Delta、sidecar/ambient 三组容易混的概念,给出后面 31 篇要反复用到的那张"配置 → xDS → Envoy"全链路图。
阅读提示:这一篇是全课程的地图,别跳。后面每篇开头都会回到这张图,标出"本篇在这里"。
第一部分 · 控制面骨架:istiod 是怎么站起来的(4 篇)
01. istiod 启动全过程:从 main() 到第一个 gRPC 端口
pilot/cmd/pilot-discovery/main.go → bootstrap.NewServer() → Server.Start()。逐段看 initKubeClient / initSecureDiscoveryService / initDiscoveryService / initControllers 的调用顺序,以及那个容易被忽略的注释:"gRPC server 必须在 CA 注册之后启动"——顺序错了会静默失败。
02. krt:Istio 自己造了一个控制器运行时
pkg/kube/krt。为什么不用 client-go 的 Informer?Collection / NewSingleton / NewCollection / NewManyCollection / Fetch 五个原语怎么组合出依赖图,Equals 如何决定要不要重算。这一篇读懂,后面所有控制器的代码都会变得"顺眼"。
03. 配置存储:一个 YAML 是怎么变成 config.Config 的
pkg/config/model.go 的 Config 结构、kind 注册表、kube/crd 客户端、informer 与 PushRequest.ConfigsUpdated。顺带厘清一个高频误解:MeshConfig 存在 ConfigMap 里,但它走的是独立的 mesh watcher(bootstrap/mesh.go 的 initMeshConfiguration),改完会触发一次 Forced 的全量推送——和 VirtualService 走的是两条完全不同的入口,不存在"改 ConfigMap 必须重启"。
04. PushContext:一次推送的"全局快照"
pilot/pkg/model/push_context.go 的 InitContext()。createNewContext() 与 updateContext() 两条路:全量重建 vs 增量复用。看清楚 initServiceRegistry / initVirtualServices / initDestinationRules / initSidecarScopes 的依赖顺序——顺序错了就是空指针。
第二部分 · 配置翻译:CRD 到内部模型(5 篇)
05. Service 与 Endpoint:服务发现的底座
pilot/pkg/serviceregistry/kube/controller、model/endpointshards.go。Service 的内部表示(host.Name、Port、Attributes)、EndpointShards 的 shard 设计、headless service 与 ServiceEntry 如何共用一套模型。
06. VirtualService:路由树是怎么排出来的
model/virtualservice.go 的 SelectVirtualServices()——命名空间、exportTo、hosts 三方匹配的优先级。然后是 MergeHTTPRoutes() 与 delegate:一个 delegate 块展开成什么,冲突判定 hasConflict() 为什么必须存在。这一篇解释"我写了却没生效"的第一大来源。
07. DestinationRule:subset、负载均衡与连接的合并算法
model/destination_rule.go。mergeDestinationRule() 的继承链(全局 → 命名空间 → subset → portLevel),MergeTrafficPolicy() 的字段级合并规则,以及 ConsolidatedDestRule 为什么要做一次"合并预计算"——这是性能关键。
08. Sidecar 资源:作用域是怎么把配置"裁剪"掉的
model/sidecar.go 的 convertToSidecarScope()。SidecarScope 决定了一个 Pod 能看到哪些 Service、VS、DR。第二大"没生效"来源就在这里:不是配置错了,是它不在你的视野里。同时解释大规模场景下 Sidecar 资源为什么是必需的。
09. Gateway API 与 Ingress:别人家的 API 怎么接进来
pilot/pkg/config/kube/gateway/controller.go。Gateway API 的 Gateway/HTTPRoute 被 krt 翻译成 Istio 的 Gateway/VirtualService,不写回集群,只存在于内存里(想看就用 /debug/configz)——所以下游的 xDS 生成器一行都不用改。看这套"转译层"设计,能学到多云 API 适配的标准做法,也能顺便解释为什么 Gateway API 的状态字段要和 Istio 自己的状态分开维护。
第三部分 · xDS 服务端:真正的核心(5 篇)
10. xDS 协议:nonce、version 与 ACK/NACK 的真相
pkg/model/xds.go 的 TypeUrl 全表,SotW 与 Delta 的语义差别,ResourceDelta 的 Subscribed/Unsubscribed/InitialResourceVersions。为什么 ISTIO_DELTA_XDS 默认已开,以及"Delta 不等于只发变化"这个官方注释到底在提醒什么。
这一篇是整个课程的协议底座。最后一部分手写服务端时,你会用到这篇里的每一个字段。建议至少读两遍。
11. ADS 连接生命周期:一个 Envoy 连上来之后发生了什么
pilot/pkg/xds/ads.go:Stream() → initConnection() → initProxyMetadata() → initializeProxy() → computeProxyState()。看懂 Connection 上挂的那些状态,就懂了为什么 istiod 能对每个代理做差异化配置。
12. 推送链路:debounce、PushQueue 与语义合并
discovery.go 的 debounce()(PILOT_DEBOUNCE_AFTER 默认 100ms、PILOT_DEBOUNCE_MAX 默认 10s)加上 pushqueue.go 的 PushQueue。回答开篇那个问题:"我改了配置,为什么不是立刻生效"——这段时间里事件被合并了几次、哪些走 shouldDebounce() 直接旁路、哪些被降级成 EDS/WDS 单独推送。
13. XdsCache:增量推送的省钱机器
model/xds_cache.go 的 Add/Get/Clear。XdsCacheEntry 接口的四个方法(Type()/Key()/DependentConfigs()/Cacheable())怎么协作、Clear(ConfigsUpdated) 的粒度为什么能做到"只失效相关项",以及缓存命中率低时该怎么调。
14. 跳过推送:ProxyNeedsPush 与依赖分析
xds/proxy_dependencies.go 的 filterRelevantUpdates()。一个 VirtualService 变更如何判断"哪些代理需要知道"。这是 Istio 能在万级 Pod 下活下来的关键之一,也是最值得抄走的设计。
第四部分 · 资源生成:先懂 Envoy,再看生成器(7 篇)
这一部分换了个起点:先讲 Envoy 到底要什么,再讲 Istio 怎么生成。不做这一步,读者只能对着
Cluster/Listener的生成代码猜"这些字段最后长什么样、为什么非得这么填"。
15. Envoy 基础:Envoy 要的到底是什么
一篇给运维和平台工程师的"Envoy 最小可用心智模型",不读 Envoy 源码,只回答四个问题:
- 一个 TCP 连接进来,Envoy 怎么走:
Listener(监听哪个端口)→FilterChain(按 SNI/ALPN/源地址挑一条链)→NetworkFilter(tcp_proxy/http_connection_manager)→Route(HTTP 才有的匹配)→Cluster(实际连去哪)→Endpoint(Cluster里那堆 IP:PORT)。五个框画成一张图,后面所有生成器代码只是往这张图上填字段。 Cluster的四个必填项:type(EDS/STRICT_DNS/STATIC的差别就是"端点从哪来")、load_assignment、transport_socket(mTLS 就是往这里塞UpstreamTlsContext)、circuit_breakers。看懂这四个,第 16 篇 CDS 里那些applyDestinationRule()才不会像魔法。- 静态配置 vs 动态配置:
bootstrap.yaml里的static_resources和dynamic_resources是谁,ads_config的作用,以及为什么 bootstrap 一旦写死在镜像里就只能靠重启换。顺带讲清node元数据(metadata/locality/id)为什么是服务端识别"你是哪个代理"的唯一入口。 - 怎么自己看:
curl localhost:9901/config_dump | jq、/clusters、/listeners、/stats四条命令,把"我下发的东西 Envoy 到底吃进去了没"变成一次自查。
动手验证:func-e run -c bootstrap.yaml 起一个空白 Envoy,用 config_dump 反查每个字段的来源,再用 curl -v 从 15000 打进去,看 Route 匹配失败时 Envoy 返回什么(这个错误信息后面排障篇会反复用)。
这一篇是为实践篇(31)降门槛的。读完它再读 16~19,脑子里有画面;直接跳到实践篇也不会一脸问号。
16. CDS:Cluster 是怎么拼出来的
networking/core/cluster_builder.go、cluster.go、cluster_tls.go。基础 cluster、subset cluster、applyDestinationRule() 的落地、metadata exchange filter 的注入条件。
17. EDS:Endpoint 与负载均衡的最后一公里
xds/endpoints/endpoint_builder.go。EndpointBuilder 的 Key()/Cacheable()、locality 与 priority failover、ep_filters.go 里的过滤链(健康检查、subset、network 视角)。
18. LDS:Listener 与 FilterChainMatch
networking/core/listener.go(一千多行,本部分最重的一篇)+ filterchain_options.go。inbound/outbound listener 的划分、FilterChainMatch 的组合爆炸问题、permissive mTLS 为什么需要那么多条 chain。
19. RDS:路由规则翻译的细节地狱
networking/core/route/route.go 的 TranslateRoute()。匹配优先级、rewrite/redirect/directResponse 的互斥、weight 与 mirror 的 Envoy 表达、retry 与 timeout 的默认值注入。
20. ECDS 与 EnvoyFilter:给自己留的后门
pkg/wasm、networking/core/extension/extensionfilter.go、networking/core/envoyfilter/ 下按资源类型拆开的四份 patch(listener_patch.go / rc_patch.go / cluster_patch.go / extension_configuration_patch.go)。EnvoyFilter 为什么被官方标成"最后手段",以及 patch 顺序的坑。
21. 性能工程:Istio 是怎么做到不炸的
把前面几篇的优化点汇总成一条线:krt 增量重算 → PushContext 增量更新 → XdsCache → 按需生成 → 跳过推送。附上 pilot/pkg/xds/testdata/benchmarks 的基准测试读法,以及真实规模下的 CPU/内存/推送耗时估算方法。
第五部分 · 数据面:sidecar 的一生(4 篇)
22. 注入:一个 Pod 是怎么被改造的
pkg/kube/inject/webhook.go + template.go。MutatingWebhookConfiguration 的匹配规则、模板渲染、istio-proxy 容器的完整定义、init 容器的 iptables 规则,以及"注入失败但 Pod 起来了"的几种典型。
23. pilot-agent:数据面里的小管家
pkg/istio-agent/agent.go 的 Run()。bootstrap 生成(generateGRPCBootstrap)、xds_proxy.go 的 xDS 转发、本地 SDS server、DNS server(initLocalDNSServer)——这个进程远比"启动 Envoy"复杂。
24. 流量劫持:iptables 与 CNI 两条路
tools/istio-iptables 的规则生成逻辑、cni/pkg/nodeagent/meshdataplane_linux.go。15001/15006/15008 三个端口的分工,为什么 CNI 模式能免特权,以及 ISTIO_META_INTERCEPTION_MODE 的实际含义。
25. 身份体系:证书是怎么从 CA 走到 Envoy 的
security/pkg/server/ca/server.go(CreateCertificate)→ agent 侧证书缓存(security/pkg/nodeagent/cache)→ security/pkg/nodeagent/sds/sdsservice.go 的 generate()。完整走一遍 CSR、签发、SDS 下发、轮换,理解 SPIFFE ID 与 trust domain。
第六部分 · Ambient:没有 sidecar 的世界(2 篇)
从 4 篇压到 2 篇(26、27)。理由:Ambient 的架构判断和 WDS 契约这两块是新的,值得细读;ztunnel 的实现细节和 HBONE 的封装协议属于"知道了能干活、不知道不影响读主干",合并成一篇讲清机制即可,不铺开 Rust 源码。
26. Ambient 全貌:分层、WDS 与什么场景该上
先讲清一件事:Ambient 不是"更轻的 sidecar",而是把L4 和 L7 拆成两跳——L4 归 ztunnel(每节点一个 DaemonSet,管 mTLS 和 TCP 转发),L7 归 waypoint(按需部署的 Envoy)。所以"要不要上 Ambient"本质是在问:你的 L7 策略(路由、鉴权、重试)覆盖多少流量?全量覆盖就等于要再摆一套 waypoint,收益会立刻打折。
架构讲完后进源码:pkg/workloadapi/workload.proto + pilot/pkg/xds/workload.go 的 GenerateDeltas()。Address/Workload 怎么替代传统 EDS,WorkloadRBACGenerator 怎么把授权策略下推,以及为什么 WDS 只能走 Delta(全量 workload 在小规模就几十 MB,SotW 每次推全量在网络上是不可接受的)。
27. ztunnel 与 HBONE:L4 数据面与它的隧道协议
istio/ztunnel 的 ARCHITECTURE.md + src/inpod、src/proxy、src/state、src/pool.rs:双 runtime(单线程 admin/XDS 与多线程 worker 隔离,避免数据面影响控制面)、in-pod 流量捕获、连接池的复用与拒绝策略。
然后是 HBONE——networking/core/listener_waypoint.go、waypoint.go、pkg/hbone/server.go 的 handleConnect() / handleDoubleConnect()。核心就一句:mTLS 里的 HTTP CONNECT,把原始 TCP 流塞进一个加密隧道,端口 15008。讲清封装/解封装、waypoint 的三种部署粒度(per-namespace / per-service / per-pod),以及为什么这个设计让 ztunnel 不需要理解 L7。
第七部分 · 用起来,以及能学到什么(3 篇)
28. 排障地图:从现象到那个函数
把 /debug/adsz、/debug/syncz、/debug/configz、/debug/endpointShardz、istioctl xds/proxy-status/analyze 串成一张决策树。三个真实案例:配置不生效、推送不到某个 Pod、mTLS 握手失败。
29. 多集群与东西向网关
pilot/pkg/serviceregistry/kube/controller 的多集群注册、initMulticluster()、east-west gateway 的配置生成。多网络 vs 多控制面,怎么选。
30. 从 Istio 学架构:五个可以立刻抄走的设计
- 声明式控制器运行时(krt):把"事件 + 重算"统一成
Collection - 推送去抖 + 语义合并:把 N 次变更压成 1 次
- 增量快照(PushContext 的 create/update 双路)
- 结果缓存 + 精确失效(XdsCache 的 key 设计)
- 按需生成 + 跳过无关推送(
ProxyNeedsPush)
每一条给出"最小可复刻版本"的伪代码,和自己的系统怎么对号入座。
第八部分 · 动手实践:手写一个 xDS 服务端(1 篇)
31. 从零写一个 xDS 服务端,让 Envoy 真的连上来
前面 31 篇一直在读别人的实现,这一篇反过来:不看 Istio,只对着 xDS 协议,把 Envoy 需要的东西造出来。目标很具体——curl localhost:10000 能通,/stats 里能看到请求数,改一次后端地址不用重启 Envoy。
分五个阶段,每个阶段都有能跑起来的产物:
阶段 0 · 先让 Envoy 起来并连上你(第 15 篇的基本功在这里全用得上) 一份最小 envoy.yaml:static_resources 里只放一个 xds_cluster 指向你的服务端,dynamic_resources 里给 ads_config(api_type: GRPC,复用 xds_cluster)。关键坑:node.id 会被服务端当成节点主键(cache.IDHash),对不上就永远收不到响应;Envoy 还会反复重连并刷 no healthy upstream 日志。
阶段 1 · 用 go-control-plane 跑通最小闭环cache.NewSnapshotCache(true, cache.IDHash{}, nil) + xds.NewServer() + 注册 ADS/CDS/EDS/LDS/RDS 四个 service + SetSnapshot()。这一版只是为了先看到 Envoy 变绿,理解"快照"这个模型:一个版本号 + 一堆资源,服务端只负责在版本变化时把 watch 唤醒。 必讲的三个约束:ADS 模式下快照必须自洽(CDS 里引用的 cluster、LDS 里引用的 route 都得在同一个快照里,否则 Envoy 会卡在 NACK 或等不到后续资源);Node ID 与 SetSnapshot 的对应关系;Consistent() 为什么必须过。
阶段 2 · 自己实现 nonce/version 状态机 把 go-control-plane 拆掉,直接实现 StreamAggregatedResources:维护每个连接的 (typeURL → {version, nonce, 上次下发的资源哈希}),收到 request 时判断它到底是"首次订阅"、"ACK"还是"NACK"(VersionInfo/ResponseNonce/ErrorDetail 三个字段怎么区分),再决定推不推、推什么。 这一段是整篇的核心——因为你会亲手踩到 xDS 最容易踩的坑:给同一份内容换了新 version 导致无限 ACK 循环;nonce 不匹配导致 Envoy 丢弃响应;只有 Delta 才有的 InitialResourceVersions。
阶段 3 · 把配置源接进来 从"硬编码快照"进化到"监听变化":用 fsnotify 盯一个 YAML 目录(或者退一步,监听 K8s Endpoints 的 informer),变化时重新生成快照、递增版本、只推变化的 typeURL。这时会自然长出 Istio 的第 12 篇(debounce)和第 14 篇(跳不跳推送)——因为你马上就会遇到"批量改 10 个文件,Envoy 被推了 10 次"。
阶段 4 · 对照 Istio 复盘 把你的实现和 pilot/pkg/xds 逐项对齐:它为什么不用 SnapshotCache 而自己写 Connection + Delta;它的 XdsCache 解决了你的什么欠缺(你的实现里,任何一次变更都要重新生成全部资源);它的 ProxyNeedsPush 在你的小规模下为什么可以省掉。读完 31 篇再回头看自己这 300 行代码,才会真的知道 Istio 复杂在哪里、哪些复杂是必要的、哪些是可以不写的。
技术栈与产物:Go + envoyproxy/go-control-plane(阶段 1)、纯 gRPC + proto(阶段 2~3)、Envoy 1.31 二进制(func-e run 一行拉起)。文末给出完整仓库结构与全部代码,可直接 git clone 跑。
这一篇是全课程的收口。如果只看一篇,看这篇;如果想真记住,前面 31 篇里至少读 10、11、12、15~19。
附录 A · 低优先级:暂时不排期
A1. Proxyless gRPC:不走 sidecar 也能用 Istio
networking/grpcgen。gRPC 客户端直接当 xDS 客户端,cds.go/lds.go/rds.go 三份生成器与 sidecar 版本差在哪(少了 iptables、少了 inbound listener,直接从 cds 拿 Cluster 用)。
为什么放附录:这套接入方式要求客户端侧改代码、换 gRPC 版本、接 xDS bootstrap,落地门槛高,实际用的人远少于 sidecar 和 Ambient。不占正文篇号、不排进度,等前面 31 篇写完、有人真需要时再补。先把主干讲透,比多一篇"用得少"的更有价值。
七、六条阅读路线
不是所有人都要 32 篇全读。按目的选:
| 目标 | 建议路线 | 篇数 |
|---|---|---|
| 只想知道 Envoy 到底在干什么 | 15 → 16 → 18 → 19 | 4 篇 |
| 快速建立全局观 | 00 → 10 → 11 → 12 → 15 → 18 → 19 → 28 | 8 篇 |
| 解决线上配置问题 | 00 → 03 → 06 → 07 → 08 → 12 → 28 | 7 篇 |
| 准备读源码 / 提 PR | 00 → 01 → 02 → 04 → 05 → 10~21 → 22 → 23 → 25 | 20 篇 |
| 评估架构选型 | 00 → 21 → 26 → 27 → 30 | 5 篇 |
| 想自己写控制面 / 网关 | 00 → 10 → 11 → 12 → 15 → 16 → 17 → 18 → 19 → 31 | 10 篇 |
第一条路线给"不打算读 Istio 源码、但被 proxy-config 输出折磨"的人一条最短路:只看 Envoy 侧四个对象和它们对应的生成器,不碰控制面骨架。
建议节奏:每周一篇。源码类内容贪多必忘,一篇读透胜过三篇略读。
八、进度
| 篇 | 标题 | 状态 |
|---|---|---|
| 00 | Istio 到底是什么:三个二进制、两类配置、一条链路 | ⏳ 规划中 |
| 01 | istiod 启动全过程:从 main() 到第一个 gRPC 端口 | ⏳ 规划中 |
| 02 | krt:Istio 自己造了一个控制器运行时 | ⏳ 规划中 |
| 03 | 配置存储:一个 YAML 是怎么变成 config.Config 的 | ⏳ 规划中 |
| 04 | PushContext:一次推送的“全局快照” | ⏳ 规划中 |
| 05 | Service 与 Endpoint:服务发现的底座 | ⏳ 规划中 |
| 06 | VirtualService:路由树是怎么排出来的 | ⏳ 规划中 |
| 07 | DestinationRule:subset、负载均衡与连接的合并算法 | ⏳ 规划中 |
| 08 | Sidecar 资源:作用域是怎么把配置“裁剪”掉的 | ⏳ 规划中 |
| 09 | Gateway API 与 Ingress:别人家的 API 怎么接进来 | ⏳ 规划中 |
| 10 | xDS 协议:nonce、version 与 ACK/NACK 的真相 | ⏳ 规划中 |
| 11 | ADS 连接生命周期:一个 Envoy 连上来之后发生了什么 | ⏳ 规划中 |
| 12 | 推送链路:debounce、PushQueue 与语义合并 | ⏳ 规划中 |
| 13 | XdsCache:增量推送的省钱机器 | ⏳ 规划中 |
| 14 | 跳过推送:ProxyNeedsPush 与依赖分析 | ⏳ 规划中 |
| 15 | Envoy 基础:Envoy 要的到底是什么 | ⏳ 规划中 |
| 16 | CDS:Cluster 是怎么拼出来的 | ⏳ 规划中 |
| 17 | EDS:Endpoint 与负载均衡的最后一公里 | ⏳ 规划中 |
| 18 | LDS:Listener 与 FilterChainMatch | ⏳ 规划中 |
| 19 | RDS:路由规则翻译的细节地狱 | ⏳ 规划中 |
| 20 | ECDS 与 EnvoyFilter:给自己留的后门 | ⏳ 规划中 |
| 21 | 性能工程:Istio 是怎么做到不炸的 | ⏳ 规划中 |
| 22 | 注入:一个 Pod 是怎么被改造的 | ⏳ 规划中 |
| 23 | pilot-agent:数据面里的小管家 | ⏳ 规划中 |
| 24 | 流量劫持:iptables 与 CNI 两条路 | ⏳ 规划中 |
| 25 | 身份体系:证书是怎么从 CA 走到 Envoy 的 | ⏳ 规划中 |
| 26 | Ambient 全貌:分层、WDS 与什么场景该上 | ⏳ 规划中 |
| 27 | ztunnel 与 HBONE:L4 数据面与它的隧道协议 | ⏳ 规划中 |
| 28 | 排障地图:从现象到那个函数 | ⏳ 规划中 |
| 29 | 多集群与东西向网关 | ⏳ 规划中 |
| 30 | 从 Istio 学架构:五个可以立刻抄走的设计 | ⏳ 规划中 |
| 31 | 从零写一个 xDS 服务端,让 Envoy 真的连上来 | ⏳ 规划中 |
| A1 | Proxyless gRPC:不走 sidecar 也能用 Istio(附录,低优先级) | 🕗 暂不排期 |
从第 00 篇开始写,一篇一个 PR。