Day 05 / 共 20 天 · 第 1 周收官

xDS-over-MCP

翻译好的 Istio 配置怎么"喂"给 istiod?今天看 MCP Generator 怎么把 config.Config 打包成 MCP Resource,通过 15051 的 gRPC 流下发给 istiod。这是 Higress→istiod 的接口,收官第 1 周。昨天(Day 04)翻译官把 Ingress 译成了 VirtualService,今天看这份文书怎么装信封、走专线寄给总部 istiod——第 1 周的最后一环,寄到之后三站(Higress/Istio/Envoy)就完整贯通了。

📍 你在 Higress 源码课的位置(第1周 全景与控制器 · 第2周 服务发现与配置)
D01 全景 D02 启动 D03 Ingress控制器 D04 配置翻译 D05 xDS-over-MCP D06 多注册中心 D07 McpBridge D08 Nacos D09 ServiceEntry D10 配置+证书
💡 本质:MCP = "用快递网络寄公文" 延续前台/总部类比——翻译官译好的文书(VirtualService)要寄给总部 istiod。MCP 就是这条现成的快递网络(xDS 协议):Higress 不用自己造物流,直接复用 istiod 的收发系统(DiscoveryServer),只需把文书装进标准信封(MCP Resource)——信封上贴好收件信息(name/namespace/时间),里面塞文书正文(Spec)。总部拆信后拿到的,和它自己从 K8s 抽屉里翻出来的文件一模一样。
L01

MCP Generator

Day 02 讲过:Higress 复用 istiod 的 DiscoveryServer,只替换六类资源的 Generator(pkg/ingress/mcp/generator.go):GatewayGenerator/VirtualServiceGenerator/DestinationRuleGenerator/EnvoyFilterGenerator/ServiceEntryGenerator/WasmPluginGenerator

Generator = "被拉取时的生成逻辑" 回想 Istio 课 Day 06-07:istiod 的 DiscoveryServer 用 Generator 生成配置。Higress 复用了整个 DiscoveryServer 框架(收发、ACK/NACK、推送队列都不用重写),只替换了"某类资源被请求时怎么生成"的 Generator。当作为客户端的 istiod(Day 01)发 MCP 请求要 VirtualService 时,就调用 Higress 的 VirtualServiceGenerator.Generate——它从 Higress 的 IngressConfig(Day 03-04 翻译出来的)取配置、打包成 MCP 格式返回。这是"复用框架 + 定制生成"的教科书案例。
L02

Generate 实现

// pkg/ingress/mcp/generator.go VirtualServiceGenerator.Generate(:82)
virtualServices := c.Environment.List(gvk.VirtualService, model.NamespaceAll)  // 从 ConfigStore 拉
return generate(proxy, virtualServices, w, updates, keepLabels, keepAnnotations)
读法:每个 Generator 只做两步:①c.Environment.List(gvk.X, ...)——从配置源拉配置(这个 List 就落到 Day 03-04 的 IngressConfig 现场翻译!);②generate 打包成 MCP 格式。ServiceEntryGenerator:49)还额外排序保证 IP 分配确定性。
L03

config → MCP Resource

// generator.go generate(:185):每个 config.Config 转成 mcp.Resource
cfg.ToProto(config.Spec)                    // config.Spec → proto body
// 填 Metadata.Name = namespace/name、CreateTime、Labels/Annotations
anypb.New(resource)                          // 打包进 discovery.Resource(:224)返回给 xDS 框架
MCP Resource = "带元信息的配置信封" config.Config(Higress 内部格式,Day 04 翻译产物)要变成 MCP 协议认的 mcp.Resourceistio.io/api/mcp/v1alpha1):把 Spec(VirtualService proto)当 body,加上 name/namespace/时间/标签,再用 anypb.New 包成 xDS 框架认的 discovery.Resource然后 DiscoveryServer 框架把它通过 gRPC 流发给 istiod。istiod 收到后拆包,就得到一个标准 Istio VirtualService——和它从 K8s 直接读的没区别。这就是 MCP 的本质:用 xDS 的信封传 Istio 配置对象。
📝 举个例子:一份 VirtualService 怎么装信封 翻译产物 config.Config(body=VirtualService,name=foo,ns=default)
ToProto(Spec):把 VirtualService 变成 proto 正文
→ 贴信封:Metadata.Name="default/foo"、CreateTime、Labels
anypb.New:塞进 discovery.Resource(xDS 快递单)
→ 15051 gRPC 流发出。istiod 拆信 → 得到一个标准 VirtualService。
L04

unknown fields 技巧

一个巧思:addExtraToUnknownFieldsgenerator.go:240)——用 proto 未定义的字段号 100 把额外 JSON(config.Extra)塞进 unknown fields,绕过 MCP Resource proto 只有 field 1/2 的限制。

怎么"偷偷"传额外信息? MCP Resource 的 proto 定义只有 field 1(metadata)和 field 2(body)——但 Higress 有些额外信息想传给 istiod。protobuf 有个特性:不认识的字段号会被当作"unknown fields"保留而非报错。Higress 就用字段号 100 塞进自己的额外 JSON——对标准 MCP 解析无害,但 Higress 定制的 istiod 能读出来。这是一个"在不破坏协议兼容性的前提下扩展协议"的黑科技。教程里点出这种技巧,能让学员理解"协议扩展"的实战手法。

👶 小白:往别人定义的 proto 里塞私货,标准的 istiod 不会报错吗?

👨‍🏫 老师:不会。protobuf 的设计里,解码器遇到不认识的字段号会默默保留、不报错(这本来是为了新旧版本兼容)。所以字段号 100 对标准 MCP 解析器就是"看不见的透明附件",只有 Higress 定制的 istiod 知道去 100 号里掏东西。就像在标准信封角落贴张只有收件人看得懂的暗号便签——邮局照常投递,外人无感。

L05

15051 gRPC

// pkg/bootstrap/server.go initGrpcServer(:369)
grpc.NewServer(...) → s.xdsServer.Register(s.grpcServer)  // 把 ADS/xDS 服务注册进 gRPC
// Start(:273):net.Listen("tcp", ":15051") + grpcServer.Serve
读法:Higress 在 15051 端口起 gRPC 服务,xdsServer.Register 把(复用的)DiscoveryServer 的 ADS 服务注册进去。istiod 通过 configSources: xds://127.0.0.1:15051(Day 01)连它。这是 Higress Core 和 istiod 的物理连接点。
L06

变更触发推送

// pkg/bootstrap/server.go initRegistryEventHandlers(:198)
// 对每种资源注册 configHandler:变更时 s.xdsServer.ConfigUpdate(pushReq)(Full push)
// ingress_config.go notifyXDSFullUpdate(:2195):
//   m.XDSUpdater.ConfigUpdate(&PushRequest{Full:true,...})
读法:Ingress/CRD/注册中心变了 → 触发 ConfigUpdate → 复用的 DiscoveryServer 走它的推送流程(Istio 课 Day 09 的 debounce/PushQueue)→ 通过 15051 推给 istiod。因为复用了 istiod 的 DiscoveryServer,连推送机制都是现成的。Day 04 的 AlwaysPushLabel 保证强制推送。
L07

全链路复盘

第 1 周大串讲:一条 Ingress 的旅程
① 用户 kubectl apply 一个 Ingress(Day 03 的 Ingress 控制器 watch 到)
onEvent 发通知(不生成),触发 ConfigUpdate(Day 04 通知/生成解耦)
③ 复用的 DiscoveryServer debounce 后,istiod(客户端)发 MCP 请求要配置
④ Higress 的 VirtualServiceGenerator.GenerateEnvironment.List → IngressConfig 现场翻译 Ingress→VirtualService(Day 04)
generate 打包成 MCP Resource → 15051 gRPC 发给 istiod(今天)
⑥ istiod 拿到 VirtualService,走它的正常 xDS 生成(Istio 课)→ 推给 Envoy(Envoy 课)
三站在这里完整贯通!Higress 生成配置 → istiod 转 xDS → Envoy 执行。
一条 Ingress 的六步旅程(你现在是这条 Ingress) ① kubectl apply Ingress 控制器 watch 到 (Day3) ② onEvent 只发通知 不生成 (Day4 解耦) ③ istiod 发 MCP 请求 来拉配置 ④ Generate→List 现场翻译 Ingress→VS (Day4) ⑤ 装信封→15051 gRPC MCP Resource (今天) ⑥ istiod→xDS→Envoy 执行转发 (Istio/Envoy 课) 关键记忆:变更只"通知",翻译到被"拉取"时才发生 —— 事件驱动 + 惰性生成
图注:把自己想成这条 Ingress,跟着 ①→⑥ 走一遍,就走通了整个第 1 周。
L08

第 1 周收官 🎓

🧠 第 1 周(全景与控制器)你已掌握

  • Day 01 AI 网关全景、寄生在 Istio 上、MCP-over-xDS、15051
  • Day 02 启动流程、initFuncList、复用 istiod 的 DiscoveryServer
  • Day 03 IngressConfig 只读 ConfigStore、六大子控制器、挂进 Environment
  • Day 04 配置翻译 Ingress→VirtualService、注解体系、金丝雀、通知/生成解耦
  • Day 05 MCP Generator、config→MCP Resource、unknown fields、全链路复盘

你现在理解了 Higress 的核心——它怎么把用户友好的 Ingress/注解翻译成 Istio 配置,通过 xDS-over-MCP 喂给复用的 istiod。第 2 周进入 Higress 的另一大特色:多注册中心服务发现。

✋ 动手

cd /Users/bitmart/work/codes/github/higress-group/higress
grep -n 'func.*Generate\|func generate\|addExtraToUnknownFields' pkg/ingress/mcp/generator.go
grep -n 'initGrpcServer\|initRegistryEventHandlers' pkg/bootstrap/server.go
明天预告 · Day 06(第2周开始)多注册中心概览——Higress 不止从 K8s 发现服务,还能从 Nacos/ZK/Eureka/Consul/DNS 发现。统一的 Watcher 抽象怎么屏蔽这些异构注册中心。
← Day 04 配置翻译 Day 06 · 多注册中心概览 →