第 06 期 / 共 10 期

Annotation 解析器深度

pkg/ingress/kube/annotations/ 的 24 个文件按主题拆开讲清楚。读完你能"加一个新注解"——这是给 Higress 添新功能最常见的姿势。

L01

annotations/ 目录

annotations/
  annotations.go      # 入口:聚合所有 Parser
  interface.go        # 接口定义
  parser.go、util.go  # 工具
  auth.go             # 鉴权类(basic/key/jwt 聚合)
  canary.go、cors.go、rewrite.go、redirect.go、timeout.go、
  retry.go、mirror.go、header_control.go、ip_access_control.go、
  local_rate_limit.go、loadbalance.go、match.go、ignore_case.go、
  default_backend.go、destination.go、downstreamtls.go、upstreamtls.go、
  http2rpc.go、mcpserver.go

24 个文件,按"一个能力一个文件"组织。注解前缀统一为 higress.io/nginx.ingress.kubernetes.io/(兼容 Nginx Ingress)。

思考:兼容 Nginx 前缀的好处是什么?答:迁移成本低。
L02

interface.go 两接口

type AnnotationsParser interface {
    Parse(annotations Annotations, config *Ingress, globalContext *GlobalContext) error
}

type AnnotationHandler interface {
    Parse(meta metav1.ObjectMeta) (*Ingress, error)
    ApplyRoute(route *networking.HTTPRoute, ingress *Ingress)
    ApplyCluster(cluster *networking.DestinationRule, ingress *Ingress)
    ApplyGateway(gw *networking.Gateway, ingress *Ingress)
}

两阶段:Parser 把字符串注解读到 Ingress IR;Applier 把 IR 字段写入 Istio 资源。这样每个能力只关心自己的字段,互不干扰。

思考:为什么 Apply 分 Route/Cluster/Gateway 三个?答:注解目标资源不同,分发更清晰。
L03

annotations.go 入口

它实例化一份 AnnotationHandler,内部维护 Parser 列表(按字段名一一对应)。Parse 流程:循环 parser.Parse() 把所有注解填到一个 Ingress 结构体。ApplyXxx 时再调每个 Parser 的同名 Apply 方法。

思考:Parser 失败时整个 Ingress 是否要拒绝?答:通常仅记录错误,继续解析其它注解,避免单点导致全停。
L04

parser.go 工具

通用工具:解析整数 / 布尔 / 字符串列表 / 时长。每个具体 parser 调用它从 Annotations map 里取值,简化错误处理。

val, err := parseIntAnnotation(annotations, "rate-limit-qps")
duration, err := parseDuration(annotations, "timeout")
list := parseStringList(annotations, "ip-whitelist")
思考:注解的类型校验放在 admission webhook 还是 controller?Higress 是后者,权衡是什么?
L05

canary 灰度

注解:higress.io/canarycanary-weightcanary-by-headercanary-by-cookie。Parser 读取后存到 Ingress.Canary 字段。Apply 阶段配合 applyCanaryIngresses 改写 HTTPRoute 的 route[] + match.headers

思考:weight + header 并用时如何排序?答:header/cookie 匹配路由先生成,未命中的请求再按权重分流。
L06

cors

注解:cors-allow-originscors-allow-methodscors-allow-headerscors-max-age。ApplyRoute 把它转成 HTTPRoute.CorsPolicy。Higress 与 Nginx Ingress 字段一一对应,迁移成本低。

思考:通配 * 与具体 origin 列表谁更安全?
L07

rewrite

注解:rewrite-targetupstream-vhost。Apply 阶段写入 HTTPRewrite.URI / Authority,让 Envoy 在路由后改写 URL。注意:rewrite 与 redirect 区别——前者改后端请求,客户端无感;后者返回 3xx。

思考:rewrite-target 支持正则替换吗?答:支持,依赖 Envoy pattern_match
L08

redirect

注解:permanent-redirectpermanent-redirect-codetemporal-redirect。直接返回 301/302/307/308。还支持 HTTPS 强制重定向 ssl-redirect

思考:ssl-redirect 在 listener 哪一层做?答:通过 VirtualService 的 HTTPRoute.Redirect。
L09

timeout

注解:proxy-connect-timeoutproxy-read-timeoutproxy-send-timeoutrequest-timeout。Apply 分别落到 HTTPRoute.Timeout(请求级)和 DestinationRule.ConnectionPool(连接级)。

思考:read 与 send 在 Envoy 里对应哪两个超时?提示:idle / response timeout。
L10

retry

注解:proxy-next-upstream-triesproxy-next-upstream(条件)。Apply 写到 HTTPRoute.Retries。Higress 默认对 5xx / connect-failure / refused-stream 自动重试。

思考:POST 请求要不要 retry?答:默认不重试,避免重复副作用。
L11

mirror

注解:mirror-target-servicemirror-percentage。流量复制到镜像服务,但响应丢弃。常用于灰度验证。Apply 落 HTTPRoute.Mirror

思考:mirror 流量是否计入 upstream 限流?
L12

header_control

统一支持请求/响应方向上的 Add/Remove/Set。Apply 落到 HTTPRoute.Headers。注意 Envoy 对 header 名大小写不敏感、值大小写敏感。

思考:怎么删除 hop-by-hop header 比如 Connection?
L13

ip_access_control

注解:whitelist-source-rangedenylist-source-range。Apply 走 EnvoyFilter(不是 HTTPRoute,因为 Istio 原生 VS 不支持 IP ACL),patch listener 加 envoy.filters.http.rbac

思考:客户端真实 IP 怎么拿?提示:x-forwarded-for + 配置 trust hop。
L14

local_rate_limit

注解:route-limit-rpsroute-limit-burst。本地 token bucket,无需 Redis,写到 EnvoyFilter envoy.filters.http.local_ratelimit

分布式限流另见 cluster-key-rate-limit 插件(第 09 期)。

思考:本地限流与集群级限流何时该用哪个?
L15

loadbalance

注解:load-balance(roundrobin/leastrequest/random/maglev/ringhash),ApplyCluster 写到 DestinationRule.TrafficPolicy.LoadBalancer。Higress 还扩展了"按 header 哈希一致性"用于 AI Provider 粘性会话。

思考:Maglev 与 RingHash 区别?答:内存结构与一致性强度不同。
L16

auth (jwt/basic/key)

auth.go 聚合多种鉴权:

  • basic-auth:Higress 原生支持,IngressConfig 合成 EnvoyFilter。
  • key-auth / jwt-auth:通过 WasmPlugin 注解 auth-enabled 关联。
  • ext-auth:调外部 authz service。
思考:注解和 WasmPlugin CRD 谁优先?
L17

upstream/downstream TLS

downstreamtls.go 处理客户端到 Higress 的 TLS(证书引用、最小 TLS 版本、SNI);upstreamtls.go 处理 Higress 到 upstream 的 mTLS(CA / cert / SNI / 验证模式)。

思考:upstream mTLS 证书放哪里?提示:Secret + DestinationRule.ClientTLSSettings。
L18

destination 转写

destination.go:注解 destination 可把 backend 重写到任意 host(含 Nacos 服务、外部 FQDN)。这是 Higress 让"Ingress 直连任意服务"的核心扩展。

思考:destination 与 backend.service.name 矛盾时谁赢?答:destination 注解优先。
L19

http2rpc / mcpserver

这两个注解把 Ingress 路由"绑定到"对应 CRD:

  • higress.io/http2rpc: my-h2r → 关联 Http2Rpc CRD,触发 Dubbo 协议转换。
  • higress.io/mcp-server-config-name: ... → 关联 McpServer CRD,转发到 MCP Server。
思考:注解 + CRD 比纯注解 / 纯 CRD 的好处?答:声明位置贴近路由,但结构化数据放 CRD。
L20

扩展新注解

5 步走:

  1. annotations/ 新建 myfeat.go,定义 MyFeatConfig 字段。
  2. 实现 AnnotationsParser 与 Apply 方法。
  3. annotations.go 注册到 parser 列表。
  4. WrapperConfig.Ingress 增加字段引用。
  5. 选择落到 Route / Cluster / Gateway 还是 EnvoyFilter,补 Apply 调用。

整套过程不需要触碰 IngressConfig 主流程,符合"开闭原则"。

本期收尾:你可以从今天起给 Higress 加新注解。下一期我们换主题:注册中心与 McpBridge。