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)就完整贯通了。
MCP Generator
Day 02 讲过:Higress 复用 istiod 的 DiscoveryServer,只替换六类资源的 Generator(pkg/ingress/mcp/generator.go):GatewayGenerator/VirtualServiceGenerator/DestinationRuleGenerator/EnvoyFilterGenerator/ServiceEntryGenerator/WasmPluginGenerator。
DiscoveryServer 用 Generator 生成配置。Higress 复用了整个 DiscoveryServer 框架(收发、ACK/NACK、推送队列都不用重写),只替换了"某类资源被请求时怎么生成"的 Generator。当作为客户端的 istiod(Day 01)发 MCP 请求要 VirtualService 时,就调用 Higress 的 VirtualServiceGenerator.Generate——它从 Higress 的 IngressConfig(Day 03-04 翻译出来的)取配置、打包成 MCP 格式返回。这是"复用框架 + 定制生成"的教科书案例。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)
c.Environment.List(gvk.X, ...)——从配置源拉配置(这个 List 就落到 Day 03-04 的 IngressConfig 现场翻译!);②generate 打包成 MCP 格式。ServiceEntryGenerator(:49)还额外排序保证 IP 分配确定性。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 框架
config.Config(Higress 内部格式,Day 04 翻译产物)要变成 MCP 协议认的 mcp.Resource(istio.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 配置对象。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。
unknown fields 技巧
一个巧思:addExtraToUnknownFields(generator.go:240)——用 proto 未定义的字段号 100 把额外 JSON(config.Extra)塞进 unknown fields,绕过 MCP Resource proto 只有 field 1/2 的限制。
👶 小白:往别人定义的 proto 里塞私货,标准的 istiod 不会报错吗?
👨🏫 老师:不会。protobuf 的设计里,解码器遇到不认识的字段号会默默保留、不报错(这本来是为了新旧版本兼容)。所以字段号 100 对标准 MCP 解析器就是"看不见的透明附件",只有 Higress 定制的 istiod 知道去 100 号里掏东西。就像在标准信封角落贴张只有收件人看得懂的暗号便签——邮局照常投递,外人无感。
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
xdsServer.Register 把(复用的)DiscoveryServer 的 ADS 服务注册进去。istiod 通过 configSources: xds://127.0.0.1:15051(Day 01)连它。这是 Higress Core 和 istiod 的物理连接点。变更触发推送
// pkg/bootstrap/server.go initRegistryEventHandlers(:198)
// 对每种资源注册 configHandler:变更时 s.xdsServer.ConfigUpdate(pushReq)(Full push)
// ingress_config.go notifyXDSFullUpdate(:2195):
// m.XDSUpdater.ConfigUpdate(&PushRequest{Full:true,...})
ConfigUpdate → 复用的 DiscoveryServer 走它的推送流程(Istio 课 Day 09 的 debounce/PushQueue)→ 通过 15051 推给 istiod。因为复用了 istiod 的 DiscoveryServer,连推送机制都是现成的。Day 04 的 AlwaysPushLabel 保证强制推送。全链路复盘
① 用户
kubectl apply 一个 Ingress(Day 03 的 Ingress 控制器 watch 到)②
onEvent 发通知(不生成),触发 ConfigUpdate(Day 04 通知/生成解耦)③ 复用的 DiscoveryServer debounce 后,istiod(客户端)发 MCP 请求要配置
④ Higress 的
VirtualServiceGenerator.Generate → Environment.List → IngressConfig 现场翻译 Ingress→VirtualService(Day 04)⑤
generate 打包成 MCP Resource → 15051 gRPC 发给 istiod(今天)⑥ istiod 拿到 VirtualService,走它的正常 xDS 生成(Istio 课)→ 推给 Envoy(Envoy 课)
三站在这里完整贯通!Higress 生成配置 → istiod 转 xDS → Envoy 执行。
第 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
Watcher 抽象怎么屏蔽这些异构注册中心。