Day 02 / 共 20 天 · 第 1 周 全景与控制器

启动流程

Higress Controller 怎么 boot?今天追启动链:cmd/higress/main.go → serve → bootstrap.NewServer → initFuncList。看它怎么把 istiod(复用)和自己的 Core 装配起来。昨天(Day 01)看的是"翻译 → 下发 → 执行"的全景,今天钻进"翻译官(Higress Core)"开机时怎么把各个部件装配好,为 Day 03 拆它的心脏 IngressConfig 铺路。

📍 你在 Higress 源码课的位置(第1周 全景与控制器 · 第2周 服务发现与配置)
D01 全景 D02 启动 D03 Ingress控制器 D04 配置翻译 D05 xDS-over-MCP D06 多注册中心 D07 McpBridge D08 Nacos D09 ServiceEntry D10 配置+证书
🤔 痛点:一个网关开机,到底要"装配"些什么? 想象你盘下一间门店要开业:得先接通水电(连 K8s)、装好收银台(xDS Server)、招好前台和门卫、贴好营业执照(证书)……漏装一样都开不了张。程序也一样——NewServer 要按顺序把七八个模块初始化好,任何一个失败都不能对外服务。今天就看这份"开业清单"。
💡 本质:initFuncList = 一张有序的"开业清单" Higress 启动的精髓不是某个魔法,而是一份按顺序执行的初始化函数列表initFuncList)。就像开业清单"先通水电、再装收银、最后办执照",每一行对应一个后续要细讲的主题。延续 Day 01 的类比:这一步是"翻译官上班前,先把办公桌、电话线(15051)、和总部的专线都接通"。
L01

入口 main

// cmd/higress/main.go:25
func main() {
  log.EnableKlogWithCobra()
  cmd.GetRootCommand().Execute()   // cobra 根命令
}
// pkg/cmd/root.go:21 higress 根命令挂 serve + version 子命令
读法:和 istiod(pilot-discovery,Istio 课 Day 02)一样的极简 cobra main。核心是 serve 子命令。
L02

serve 命令

// pkg/cmd/server.go getServerCommand RunE(:68)
server, _ := serverProvider(args)   // → bootstrap.NewServer(args)
server.Start(stop)
waitForMonitorSignal(stop)           // 阻塞等信号
读法:又是"构造 → Start → 等信号"的启动三段(和 Envoy/Istio 课一致)。serverProvider 指向 bootstrap.NewServer
L03

关键端口

// pkg/cmd/server.go 默认参数(:89-103):
GrpcAddress: ":15051"       // ★ istiod 连接的 MCP/xDS 端口(Day 01)
HttpAddress: ":8888"        // debug/ready
CertHttpAddress: ":8889"    // 证书 ACME
NativeIstio: true
// flag(:105):ingressClass 默认 higress、gatewayHttpPort=80、gatewayHttpsPort=443…
15051 是 Higress Core 的"对外接口" 回想 Day 01:15051 是 Higress Core 起的 MCP Server 端口,istiod 连它拉配置。就像 istiod 用 15012 对 Envoy 服务(Istio 课 Day 02),Higress Core 用 15051 对 istiod 服务。三个端口串起三层:Higress Core(15051) → istiod(15012) → Envoy。8888 是就绪探针(Day 07)、8889 是证书 ACME 挑战(Day 10)。ingressClass=higress 决定 Higress 只处理标了这个 class 的 Ingress。
三个端口串起三层(每层各管一段接线) Higress Core :15051 对 istiod 服务 istiod :15012 对 Envoy 服务 Envoy 门卫 真正转发流量 另外 :8888 就绪探针 · :8889 证书 ACME
图注:15051 是本课主角 Core 的"对外电话";15012/Envoy 是你 Istio/Envoy 课已学的下游。
L04

Server 结构

// pkg/bootstrap/server.go:136 Server
type Server struct {
  environment      *model.Environment          // Istio 的!
  configController  model.ConfigStoreController // Higress 的 IngressConfig
  xdsServer        *xds.DiscoveryServer         // 直接复用 Istio 的 DiscoveryServer!
  certServer       *cert.Server
  ...
}
读法:关键:Server 内嵌的 environmentxdsServer 都是 Istio 的类型model.Environmentxds.DiscoveryServer)——Higress 直接复用它们!Higress 自己写的是 configController(IngressConfig,Day 03)和 certServer这坐实了"寄生":Higress 借用 Istio 的骨架。
L05

initFuncList

// pkg/bootstrap/server.go NewServer(:152)核心:初始化函数列表(:169)
initFuncList := []func() error{
  s.initKubeClient, s.initXdsServer, s.initHttpServer,
  s.initConfigController, s.initRegistryEventHandlers,
  s.initAuthenticators, s.initAutomaticHttps,
}
initFuncList = "装配清单" NewServer 按这个列表顺序初始化各模块——这是理解 Higress 启动的最佳骨架。①initKubeClient(连 K8s)②initXdsServer(复用 istiod 的 DiscoveryServer + 换 Generator,Day 05)③initHttpServer ④initConfigController(建 IngressConfig,Day 03)⑤initRegistryEventHandlers(配置变更触发推送)⑥initAuthenticators(认证 istiod 客户端)⑦initAutomaticHttps(证书,Day 10)。每个 init 函数对应后面某一天的主题。这种"init 函数列表"是 Go 项目常见的清晰装配方式(Istio 课 Day 02 也是)。
📝 举个例子:开业清单 → 对应哪天学 initConfigController → 建起翻译官的心脏 IngressConfig(Day 03);
initXdsServer → 复用 istiod 的 DiscoveryServer 并换 6 类 Generator(Day 05);
initRegistryEventHandlers → 配置一变就触发推送(Day 05/07);
initAutomaticHttps → 自动办 HTTPS 证书(Day 10)。
所以这份清单其实就是"本周的课程表"——每装一个部件,就预告了后面某一天。
L06

复用 istiod

// initXdsServer(server.go:342):
s.xdsServer = xds.NewDiscoveryServer(s.environment, ...)  // Istio 的 xDS server
// 逐类型注册 Higress 自己的 MCP Generator(:346):
s.xdsServer.Generators[gvk.Gateway.String()]        = &mcp.GatewayGenerator{...}
s.xdsServer.Generators[gvk.VirtualService.String()] = &mcp.VirtualServiceGenerator{...}
// … 六类:Gateway/VirtualService/DestinationRule/EnvoyFilter/ServiceEntry/WasmPlugin
s.xdsServer.ProxyNeedsPush = func(...) { return req, true }  // 永远推送(下游是 istiod)
读法:Higress 不重写 xDS 协议栈——直接 new 一个 Istio 的 DiscoveryServer,只替换六类资源的 Generator(改成从 Higress 的 ConfigStore 生成 MCP Resource,Day 05)。ProxyNeedsPush 改成"永远推"——因为下游是 istiod(一个客户端)而非成千 Envoy,不需要 proxy 级裁剪。这是"复用框架 + 定制生成逻辑"的极致体现。

👶 小白:ProxyNeedsPush 改成"永远推",不会把 istiod 累死吗?

👨‍🏫 老师:不会。原生 istiod 面对成千上万个 Envoy,得精挑细选"这次配置变化跟你有没有关系",省带宽。但 Higress 的 15051 下游只有一个客户端——istiod 本身。既然只有一个订阅者,判断"要不要推"纯属浪费,干脆一律推给它、让它自己合并。就像群发通知只有一个收件人,就不必再筛收件人名单了。

L07

Start 与就绪

Start()server.go:273):net.Listen("tcp", ":15051") + grpcServer.Serve(对 istiod 服务)。就绪探针 readyHandler:454)在 :8888/ready,探测 xDS server ready。HasSynced 要所有子控制器同步才 ready。

读法:和 istiod 的 ready 门禁(Istio 课 Day 02)一个道理——所有配置控制器(Ingress/CRD/注册中心)都同步好了,才对 istiod 提供服务,否则会喂不完整的配置。
L08

今日小结 + 动手

🧠 今天你应该能回答

  • 启动链 main → serve → NewServer 的结构?
  • 15051/8888/8889 各是什么端口?
  • Server 结构里哪些是 Istio 的、哪些是 Higress 的?
  • initFuncList 的七个 init 函数各干什么?
  • Higress 怎么"复用 istiod 的 DiscoveryServer"?ProxyNeedsPush 为什么改成永远推?

✋ 动手

cd /Users/bitmart/work/codes/github/higress-group/higress
sed -n '25,31p' cmd/higress/main.go
grep -n 'GrpcAddress\|initFuncList\|func.*NewServer' pkg/cmd/server.go pkg/bootstrap/server.go
sed -n '342,367p' pkg/bootstrap/server.go
明天预告 · Day 03Ingress 控制器核心——Higress 自己的心脏 IngressConfig:它是一个只读的 Istio ConfigStore,聚合了 6 个子控制器(Ingress/Gateway/McpBridge/WasmPlugin/Http2Rpc/ConfigMap)。
← Day 01 全景 Day 03 · Ingress 控制器核心 →