Ingress 与 Gateway API:七层流量的入口演进
Service 把集群内部的流量调度问题解决了,但把服务暴露到集群外部的 HTTP/HTTPS 流量需要另一层抽象。NodePort 和 LoadBalancer 都在四层工作——它们能把外部 TCP 流量转发进来,但无法根据 HTTP 的 Host 头或 URL 路径做路由决策,也无法终止 TLS、做 URL 重写、实现金丝雀发布。Ingress 就是 Kubernetes 为七层 HTTP 路由设计的原生对象,它在 1.1 版本进入 alpha,1.19 版本 GA,至今仍是绝大多数集群的 HTTP 入口方案。
Ingress 的设计在简单场景里非常直观:声明哪个 host + 哪个路径对应哪个 Service,TLS 证书放在 Secret 里引用,一个 Controller(Nginx、Traefik、HAProxy 等)负责把这些规则翻译成实际的反向代理配置。这套模型在业务不复杂时运作良好,但当需要金丝雀发布、基于请求头的路由、跨命名空间的服务暴露、gRPC 原生路由时,规范本身的表达能力不够,各家 Controller 用 annotation 扩展——结果是注解的命名空间各异、行为各异,把路由配置和特定 Controller 深度绑定,换一个 Controller 就要重写所有高级配置。
Gateway API 是 Kubernetes SIG Network 对这个问题的系统性回答,从设计层面解决 Ingress 的扩展性困境。它把 L7 入口的职责拆分成三个独立对象、三个独立角色:基础设施提供者定义 GatewayClass(用哪种技术实现),集群管理员创建 Gateway(在哪个端口监听、用什么证书),应用开发者写 HTTPRoute(哪些路径路由到哪些后端)。金丝雀发布、请求头匹配、流量镜像、URL 重写都是 HTTPRoute 的标准字段,不依赖任何 annotation。Gateway API 的 core API 在 Kubernetes 1.28 正式 GA,是七层流量入口的下一个标准。
架构对比图
1 | |
Ingress 对象模型
Ingress 对象的结构由 networking.k8s.io/v1 API 定义,核心字段是 rules 和 tls。
rules 列表里每条规则包含一个 host(域名,支持通配符 *.example.com)和一组 http.paths,每条 path 指定匹配类型(Prefix、Exact、ImplementationSpecific)和后端 Service。最简单的用法是:所有 api.example.com 的 / 前缀请求转发到 api-service:80。
Prefix 匹配是前缀匹配,但有一个容易踩坑的细节:匹配是按路径 segment 边界进行的,而不是纯字符串前缀。/api 这条规则会匹配 /api、/api/、/api/v1,但不会匹配 /apiv2(因为 apiv2 不是以 / 分隔的合法路径扩展)。Exact 是精确匹配,/api 只匹配 /api,不匹配 /api/。ImplementationSpecific 把匹配行为委托给 IngressClass 对应的 Controller,行为取决于具体实现,不保证可移植性——这是历史遗留的兼容选项,新配置不建议使用。
tls 字段引用一个包含 TLS 证书的 Secret,Ingress Controller 读取证书,在自己监听的 443 端口终止 TLS,把解密后的 HTTP 请求转发给后端 Service(TLS offloading)。Secret 里的证书需要提前创建(手动、cert-manager 自动颁发,或从外部 PKI 同步),Ingress 只是引用。Secret 和 Ingress 通常要在同一个命名空间里,这是 Ingress TLS 跨命名空间使用的障碍之一。
ingressClassName 字段(1.18 引入,取代旧的 kubernetes.io/ingress.class annotation)指定由哪个 IngressClass 处理这条 Ingress,IngressClass 对象里 spec.controller 字段写 Controller 的标识符。这允许集群里同时运行多个 Ingress Controller(如外部流量用 Nginx、内部流量用 Traefik),每个 Controller 只处理自己 IngressClass 的规则。如果不指定 ingressClassName,但某个 IngressClass 设置了 kubernetes.io/ingress.class: "nginx" annotation 为默认,则这条 Ingress 也会被该 Controller 处理。
Ingress 本身不定义任何实现,它是一份声明。Controller 的 Informer 监听 Ingress 对象变化,把规则翻译成反向代理配置,执行热重载。Nginx Ingress Controller 把规则翻译为 nginx.conf 里的 server block 和 upstream 块,每次变化调用 nginx -s reload(Nginx 的 reload 不中断已有连接,但配置错误会导致 reload 失败,请求会停止路由)。Traefik 则用动态配置提供者(Kubernetes Ingress Provider),实时更新内存中的路由表,不需要 reload。
Ingress 的局限
Ingress 规范能覆盖的路由能力有限,面对真实业务需求时很快触及边界。
金丝雀发布(把 X% 流量路由到新版本)是最常见的需求之一,Ingress 规范没有定义任何权重字段。Nginx Ingress Controller 通过 annotation nginx.ingress.kubernetes.io/canary: "true" 和 nginx.ingress.kubernetes.io/canary-weight: "20" 实现,但 Traefik 的 annotation 完全不同(通过 TraefikService CRD 实现权重),HAProxy 又是另一套机制。换 Controller 时,金丝雀配置必须完全重写。
请求头路由(根据 X-User-Region 或 X-Feature-Flag 路由到不同后端)同样不在 Ingress 规范里,各 Controller 的 annotation 行为不一致。基于请求头的路由在灰度发布、A/B 测试、多租户隔离场景里极为普遍,但 Ingress 规范的缺失迫使团队用 annotation 实现,形成 Controller 锁定。
跨命名空间路由——应用团队在 namespace A 里的 Ingress 想引用 namespace B 里的 Service——Ingress 规范没有授权机制,多数 Controller 要么不支持,要么通过非标准方式实现,存在安全隐患(任何能创建 Ingress 的团队都可能引用其他命名空间的服务)。
TLS 证书管理:Ingress 引用的 Secret 必须与 Ingress 在同一命名空间(1.22 之前强制要求),跨命名空间共用证书无法用 Ingress 原生实现,需要把证书同步到每个命名空间(cert-manager 有专门的 ClusterIssuer 机制处理这个问题,通过 reflector 或 external-secrets 同步证书到多个命名空间)。
多团队协作时,Ingress 的职责边界不清晰也是问题。基础设施团队负责 Ingress Controller 的部署和维护,业务团队负责写 Ingress 规则,但两者都在同一个 Ingress 对象里——业务团队写 annotation 时可以意外(或有意)修改影响 Controller 全局行为的配置,基础设施团队无法轻松审计或限制哪些 annotation 允许使用。
这些局限的根本原因是 Ingress 的设计把"基础设施配置"(用哪个 Controller、监听哪个端口)、“策略配置”(限流、认证)、“路由配置”(路径、权重)全部揉进一个对象和一套 annotation,没有职责分离,导致任何高级能力都必须通过 Controller 私有的 annotation 扩展,无法在不同 Controller 之间移植。
Gateway API 对象模型
Gateway API 由四个核心对象构成,分别对应不同的关注层次和管理角色。
GatewayClass 定义"网关用什么技术实现",由基础设施提供者管理(通常是平台团队或 SRE)。spec.controllerName 字段写 Controller 的标识符(如 gateway.envoyproxy.io/gatewayclass-controller),告诉集群里哪个 Controller 负责实现从这个 GatewayClass 创建的 Gateway。一个集群可以有多个 GatewayClass,对应不同的技术选型(Envoy Gateway、Cilium Gateway、Nginx Gateway Fabric 等)。GatewayClass 是集群级别的资源,不属于任何命名空间。
Gateway 定义"网关实例在哪里监听",由集群管理员管理。spec.gatewayClassName 引用对应的 GatewayClass,spec.listeners 列表里每个 listener 指定协议(HTTP/HTTPS/TLS/TCP)、端口、TLS 证书(Secret 引用,支持跨命名空间引用)、以及允许哪些命名空间的 Route 附加(allowedRoutes.namespaces)。Gateway 是 Kubernetes 对物理网关实例(云 LB、Envoy 实例、Nginx Pod)的声明式抽象,Controller 读取 Gateway 对象,创建真实的网关资源。Gateway 可以部署在 infra 或 gateway-system 命名空间,与业务命名空间分离。
HTTPRoute 定义"HTTP 请求如何路由",由应用开发者管理,可以部署在自己的命名空间里。spec.parentRefs 引用 Gateway(可以跨命名空间,需要 Gateway 的 allowedRoutes 允许,或者有 ReferenceGrant 授权),spec.rules 里写匹配条件(path、header、query、method)和后端 Service。权重分配、URL 重写、请求头修改、流量镜像都是 HTTPRoute 的标准字段。HTTPRoute 附加到 Gateway 后,Controller 把路由规则合并进网关实例的配置,实时生效。
ReferenceGrant 解决跨命名空间引用的安全问题:如果 HTTPRoute 要引用另一个命名空间的 Service,目标命名空间必须存在一个 ReferenceGrant 对象,明确授权哪个命名空间的哪种对象可以引用本命名空间的哪种资源。没有 ReferenceGrant,跨命名空间引用被拒绝,防止命名空间间的未授权访问。ReferenceGrant 的 spec.from 字段描述允许引用的来源(命名空间 + 资源类型),spec.to 字段描述被允许引用的目标(命名空间 + 资源类型)。这是一种明确的、基于意图的授权机制,比 Ingress 里隐式允许跨命名空间引用的安全模型更严格。
HTTPRoute 的路由能力
HTTPRoute 的 rules 字段支持丰富的匹配条件,是 Gateway API 相对于 Ingress 规范能力大幅跃升的核心。
path 匹配:PathPrefix(前缀匹配)、Exact(精确匹配)、RegularExpression(正则,需要 Controller 扩展支持)。语义与 Ingress 的 path 类型基本一致,PathPrefix 同样按 segment 边界匹配。
headers 匹配:精确匹配(Exact)或正则匹配请求头,如 X-Env: canary。可以用来实现基于环境标签的流量分割,无需修改 URL。多个 headers 条件是 AND 关系,需要全部满足才匹配。这个能力在 Ingress 里需要 annotation 实现,且各 Controller 语法不同;HTTPRoute 把它定义为标准字段,任何符合规范的 Controller 行为一致。
queryParams 匹配:匹配 URL 查询参数,适合 A/B 测试场景(?variant=new)。
method 匹配:GET、POST、DELETE 等 HTTP 方法过滤。可以把写操作(POST/PUT/DELETE)路由到不同的后端 Service,读操作(GET)路由到另一个后端,实现读写分离的路由策略。
backendRefs 里支持多个后端,每个后端有 weight 字段。权重 90/10 实现金丝雀,权重 50/50 实现 A/B 测试,都是标准字段,不依赖任何 annotation。权重不需要加和为 100,Controller 会自动归一化,weight: 1 和 weight: 9 的效果与 10% 和 90% 完全相同。
filters 字段支持请求/响应转换:RequestHeaderModifier(添加/删除/修改请求头)、ResponseHeaderModifier、RequestRedirect(HTTP 重定向,包含状态码、目标 host、scheme、path 的完整控制)、URLRewrite(重写 URL path 或 host,支持正则替换)、RequestMirror(把请求镜像到另一个 Service,用于影子测试——主请求正常响应,镜像请求的响应被忽略,但可以触发新版本的处理逻辑)。
RequestMirror 是一个特别有价值的能力:在不影响生产流量的前提下,把真实请求复制一份发到待上线的新版本 Service,验证新版本的行为是否符合预期。这在高风险变更发布前的验证阶段极为有用,Ingress 没有任何对应的标准能力。
这些能力在任何符合 Gateway API 规范的 Controller 里行为一致,切换 Controller 时 HTTPRoute 配置无需修改。
TCPRoute、GRPCRoute 与协议扩展
Ingress 只支持 HTTP/HTTPS,TCP/UDP 流量需要借助 Controller 的私有 CRD 或 Service 的 NodePort。Gateway API 通过扩展协议路由类型解决这个问题。
TCPRoute:在 Gateway 的 TCP 监听端口上,基于端口号把流量路由到后端 Service。适合数据库端口转发、SSH 隧道等非 HTTP 场景。在 Gateway API 1.0 里属于 Experimental 级别,随着实现成熟度的提升,预计未来会升为 Standard。TCPRoute 和 HTTPRoute 可以挂载到同一个 Gateway 实例的不同 listener 上,Gateway 根据监听端口的协议类型决定交给哪种 Route 处理。
GRPCRoute:GA 自 Gateway API 1.1,专门为 gRPC 流量设计。支持按 gRPC 服务名(com.example.UserService)和方法名(GetUser)路由,这是 HTTPRoute 做不到的精度(HTTP path 层面 gRPC 的 URL 结构是 /{package}.{service}/{method},可以用 path 模拟,但语义不如 GRPCRoute 清晰)。GRPCRoute 还正确处理了 gRPC 流式请求(server-streaming、client-streaming、bidirectional-streaming),这些场景在 HTTP/2 层面有特殊的生命周期语义,普通 HTTPRoute 的超时和重试策略需要额外注意。
UDPRoute:用于 UDP 协议的端口路由,适合 DNS、QUIC 等场景,处于 Experimental 级别。UDP 的无状态特性使路由策略与 TCP 不同:没有连接建立握手,无法做连接级别的亲和性,每个 UDP 数据报独立路由。
所有这些路由类型共享同一个 Gateway 实例,只需在 Gateway 的 listeners 里开对应协议的监听端口,无需为每种协议单独部署一个 Controller。这使得网关资源可以集中管理,减少运维开销。
Policy Attachment 机制
Gateway API 把策略(限流、认证、重试、超时)与路由规则分离,通过 Policy Attachment 机制实现。策略写在独立的 Policy 对象里(如 BackendLBPolicy、BackendTLSPolicy,各 Controller 也可以扩展自己的 Policy 类型),通过 targetRef 引用 Gateway、HTTPRoute 或 Service,附加到对应层次。
Policy Attachment 支持继承和覆盖语义:附加到 Gateway 的策略对该 Gateway 下所有 HTTPRoute 生效(默认继承),附加到特定 HTTPRoute 的策略只对那条 HTTPRoute 生效,且可以覆盖 Gateway 级别的策略。这种层次覆盖模型与 RBAC 的继承语义类似,方便平台团队设定全局默认值,业务团队针对特定路由做覆盖。
BackendTLSPolicy 管理网关到后端 Service 之间的 TLS 配置(端到端加密),指定后端的 CA 证书和 SNI。这解决了一个常见的安全需求:外部客户端到网关之间有 TLS(frontend TLS),网关到后端 Service 之间也要有 TLS(backend TLS / mTLS),两段加密独立配置。Ingress 没有标准方式配置 backend TLS,各 Controller 的 annotation 语法各异。
BackendLBPolicy 定义网关向后端 Service 的负载均衡策略,包含会话亲和性(Session Persistence)和超时配置。会话亲和性的类型包括基于 Cookie 的(网关插入 cookie,同一 cookie 的请求路由到同一后端)和基于 Header 的(根据特定请求头做亲和性决策)。这比 Service 的 sessionAffinity: ClientIP 更灵活,不受 SNAT 影响(ClientIP 亲和性在经过多次 SNAT 后源 IP 可能丢失,cookie 不受影响)。
这种设计使策略和路由规则各自独立演进:平台团队可以给 Gateway 附加全局限流策略,应用团队可以给自己的 HTTPRoute 附加针对特定路径的认证策略,两者互不干扰。Ingress 里的 annotation 把策略和路由混在一起,任何策略变更都必须修改 Ingress 对象,没有职责分离。
cert-manager 与证书管理
TLS 证书的自动化管理在 Ingress 和 Gateway API 里都是关键实践,cert-manager 是最广泛使用的证书管理工具。
cert-manager 以 Deployment 形式部署在集群里,通过 CRD(Issuer、ClusterIssuer、Certificate、CertificateRequest)描述证书颁发策略。ClusterIssuer 跨命名空间生效,配置 Let’s Encrypt 的 ACME 端点和 DNS/HTTP challenge 方式;Issuer 命名空间级别,适合内部 PKI 场景。
对 Ingress 的集成:cert-manager watch Ingress 对象的 tls 字段,如果对应 Secret 不存在或临近过期,自动触发证书申请流程,把新证书写入 Secret,Ingress Controller 重新加载。整个过程对用户透明,只需在 Ingress 上加 cert-manager.io/cluster-issuer: "letsencrypt-prod" annotation 即可。
对 Gateway API 的集成:cert-manager 1.15+ 原生支持 Gateway API 的 listener TLS,通过 kubernetes.io/tls 类型的 Secret 为 Gateway listener 提供证书。Gateway 的 certificateRefs 字段引用这个 Secret,cert-manager 自动维护证书的续期。
可运行实验
1 | |
实验结果映射
cat /etc/nginx/nginx.conf | grep -A 5 upstream 显示 Nginx Ingress Controller 为每个 Service 生成的 upstream 块,包含所有就绪 Pod 的 IP:port。每次 Ingress 或 Endpoints 变化,Controller watch 到事件后重新生成配置并调用 nginx -s reload。reload 是 Nginx 的热重载机制——master 进程加载新配置,旧 worker 进程处理完已有连接后退出,新 worker 进程接管新连接,全程无连接中断(除非新配置有语法错误导致 reload 失败)。
金丝雀 Ingress 的 annotation canary-weight: "20" 被 Nginx Controller 翻译为 upstream 的概率权重,用 $random_variable 或 split_clients 模块实现,在 nginx.conf 里可以看到对应的分割逻辑。发 50 个请求后,到 canary(httpd,返回 Apache 字样)的请求数量应该接近 10(20%),但因为样本量小,实际分布会有偏差。
kubectl describe ingress demo 的 Events 字段显示 Controller 处理这条 Ingress 的日志:认领时间、同步时间、是否有 annotation 解析错误。如果 ingressClassName 配置错误或 IngressClass 不存在,Events 里会看到"无法找到 IngressClass"的错误,Ingress 不会被任何 Controller 处理——这是 Ingress 对象"创建成功但完全无效"的经典场景,Events 是诊断的第一入口。
Gateway API 的 HTTPRoute 权重路由不需要创建两个独立的 Route 对象(不像 Nginx 金丝雀需要 demo + demo-canary 两个 Ingress),在同一条 HTTPRoute 的 backendRefs 里直接声明多个后端和权重,配置更简洁,意图更清晰。
模式提炼
Ingress 是"一个对象解决所有问题"的设计,代价是高级能力靠 annotation 扩展,annotation 不标准化导致 Controller 锁定。Gateway API 是"职责分离"的设计:GatewayClass(什么技术)、Gateway(在哪监听)、HTTPRoute(怎么路由)三个对象各自独立,各自由对应角色管理,各自可以独立变更而不影响其他层。
这种分离的价值在大型组织里体现最明显:平台团队管理 GatewayClass 和 Gateway,确保网关基础设施的安全和稳定;各业务应用团队自主管理 HTTPRoute,配置自己的服务路由规则,不需要申请平台团队的介入。Ingress 模型里,一个 Ingress 对象同时涉及基础设施配置(ingressClassName)和路由配置(rules、annotations),业务团队改路由规则时可能无意中影响基础设施配置,职责边界不清晰。
这种角色分离也使审计和访问控制更精确:RBAC 可以精细控制"谁能创建 HTTPRoute"和"谁能创建 Gateway",而不必在同一种对象上混杂两种权限需求。在大型企业里,网关基础设施和业务路由配置通常是不同团队负责的,Gateway API 的对象边界与组织结构自然对应。
选型决策:现有集群已用 Ingress 且路由需求简单,不需要强制迁移,Ingress 继续可用;新集群或需要金丝雀、gRPC 路由、跨命名空间路由、细粒度策略管理时,Gateway API 是更清晰的选择。两者可以在同一集群共存,不存在互斥关系。
工程迁移表
| 传统技术 / Ingress 概念 | Gateway API 对应物 | 差异说明 |
|---|---|---|
Nginx server { } 块 |
Gateway listener | Nginx 手动配置,Gateway 由 Controller 从对象生成 |
Nginx upstream { weight } |
HTTPRoute backendRefs[].weight |
标准字段,跨 Controller 可移植 |
Nginx proxy_pass / rewrite |
HTTPRoute filters.URLRewrite |
标准字段,Ingress 里依赖 annotation |
| Traefik middleware | Policy Attachment(扩展) | 语义相近,Gateway API 通过策略对象分离 |
| 多 Ingress Controller | 多 GatewayClass | GatewayClass 显式声明每个 Controller 的技术实现 |
| IngressClass | GatewayClass | 角色相似,GatewayClass 额外携带实现语义 |
| cert-manager + Ingress TLS | cert-manager + Gateway TLS | cert-manager 同时支持两种,Gateway 语义更清晰 |
| Kong/APISIX API Gateway | GatewayClass(Kong/APISIX 实现) | Kong/APISIX 已提供 Gateway API Controller 实现 |
常见误解
误解一:Ingress Controller 就是 Ingress。
Ingress 资源(kind: Ingress)只是一个声明性对象,描述路由规则,没有任何执行能力。Ingress Controller 是一个独立部署的 Pod(通常是 Deployment),它 watch Ingress 对象,把规则翻译成反向代理配置。如果集群里没有任何 Ingress Controller,Ingress 对象可以正常创建,但完全没有效果——没有任何流量被路由,也没有任何错误报出(除非 admission webhook 做了检查)。Ingress 和 Ingress Controller 是一对多的关系:一个 Ingress 资源被某一个 Controller 处理,由 ingressClassName 字段决定。
误解二:Gateway API 是 Ingress v2,Ingress 即将废弃。
Gateway API 是一个独立的 API 组(gateway.networking.k8s.io),不是 Ingress 的新版本,也不会直接替换 Ingress。Kubernetes 官方没有给出 Ingress API 的废弃时间表,Ingress 在 1.19 GA 后一直处于稳定状态。Gateway API 和 Ingress 可以在同一集群里长期共存,甚至可以用同一个 Controller 同时支持两种 API(如 Nginx Gateway Fabric 同时支持 Ingress 和 HTTPRoute)。迁移到 Gateway API 是一个自愿的演进选择,不是强制要求。
误解三:只有 HTTPS 流量才需要 Ingress,HTTP 流量用 NodePort 就够了。
Ingress 不仅用于 HTTPS。HTTP 流量的 Host 头路由(多个域名共用一个 LB IP)、URL path 路由(/api 到 Service A,/static 到 Service B)都需要七层路由能力,NodePort 和 LoadBalancer 做不到这些。用 NodePort 暴露多个服务需要每个服务占用一个节点端口(30000-32767 范围),端口耗尽且难以管理;Ingress 共享一个 443/80 端口,用 Host/path 区分,是更可扩展的外部访问方式。
误解四:Gateway API 需要替换整个 Ingress Controller,迁移成本高。
大多数主流 Ingress Controller 已经同时支持 Ingress 和 Gateway API,不需要替换基础组件。Nginx Gateway Fabric、Traefik、HAProxy Ingress、Contour 都同时实现了两种 API,可以在同一个集群里逐步把高流量或复杂路由的 Ingress 迁移到 HTTPRoute,低流量或简单路由的 Ingress 保持不动,双轨并行。这使得迁移是渐进式的,没有"大爆炸"式替换的风险。
练习
练习一:在 kind 集群部署 Nginx Ingress Controller,创建两个不同 host 的 Ingress 规则(app1.local 和 app2.local,通过 /etc/hosts 模拟),用 curl -H "Host: ..." 分别测试。进入 Controller Pod 查看 nginx.conf,找到为这两个 host 生成的 server { } 块,理解 Nginx 如何把多条 Ingress 规则合并成一个配置文件。
练习二:用 Nginx Ingress 的金丝雀 annotation 配置 30% 流量到新版本,然后写一个脚本发送 200 个请求,统计路由到 stable 和 canary 的请求数量,验证实际比例与配置接近 70/30。改变 canary-weight 值重复实验,观察规则更新后流量分配的变化速度。
练习三:安装 Gateway API CRD(kubectl apply -f standard-install.yaml),阅读 GatewayClass、Gateway、HTTPRoute 的 CRD 字段定义,对比 Ingress 的字段,找到三个 Ingress 规范里没有而 HTTPRoute 规范里有的标准字段,分析这三个字段在 Ingress 模型里需要用哪些 annotation 实现(以 Nginx Ingress Controller 为例)。
练习四:在两个命名空间(infra 和 app)里分别创建一个 Gateway 和一个 HTTPRoute,让 HTTPRoute 通过 parentRefs 引用 infra 命名空间的 Gateway,观察没有 ReferenceGrant 时的错误信息。然后在 infra 命名空间创建 ReferenceGrant 授权 app 命名空间引用,确认跨命名空间路由成功建立。
Ingress Controller 横向对比
主流 Ingress Controller 各有侧重,选型时需要结合已有技术栈和功能需求。
Nginx Ingress Controller(kubernetes/ingress-nginx)是社区使用最广泛的实现,基于 OpenResty(Nginx + Lua 扩展),支持丰富的 annotation 配置金丝雀、限流、认证、mTLS 等功能。热重载(nginx -s reload)是其主要弱点:每次 Ingress 或 Endpoint 变化都触发配置重载,在 Pod 快速扩缩容的场景下,频繁 reload 会导致短暂的连接中断。nginx-ingress-controller 的 Lua 脚本支持动态上游更新(endpoints 变化时不触发 reload),但 Ingress 规则本身的变化(host/path 修改)仍需 reload。
Traefik 是另一个常见选择,采用动态配置提供者(Kubernetes CRD 模式),路由规则变更实时生效,不需要进程 reload,对频繁变更场景更友好。Traefik 的 IngressRoute CRD 表达能力远强于原生 Ingress spec(支持中间件链、TCP/UDP 路由、gRPC),但这些 CRD 不可移植到其他 Controller。Traefik 3.x 开始原生支持 Gateway API。
HAProxy Ingress Controller 适合对性能要求极高的场景。HAProxy 本身是业界性能标杆的四/七层代理,支持主动健康检查(主动探测后端,而不是依赖 readinessProbe 的被动摘除)、精细的连接和超时配置、基于服务器权重的细粒度负载均衡。HAProxy Ingress 也支持 Gateway API。
Envoy Gateway 是 CNCF 孵化的 Gateway API 参考实现,基于 Envoy 代理,主攻 Gateway API 的完整实现而非 Ingress 兼容。Envoy 在服务网格(Istio sidecar 就是 Envoy)和 API 网关领域积累了大量生产验证,性能和可观测性(Envoy 内建 Prometheus 指标、zipkin/jaeger 追踪集成)是其优势。
Cilium Gateway API 是 Cilium 在提供 CNI 能力之外叠加的网关能力,使用 eBPF 在内核数据路径完成路由决策,不需要独立的代理进程,延迟更低。已经使用 Cilium 作为 CNI 的集群,使用 Cilium Gateway 是自然的选择——CNI 和网关功能由同一个控制面管理,减少运维复杂度。
选型建议:已有 Nginx 运维经验且需要快速上手选 nginx-ingress-controller;需要 Gateway API 且追求零停机配置更新选 Traefik 或 Envoy Gateway;性能极限场景选 HAProxy;已用 Cilium 的集群优先考虑 Cilium Gateway。
TLS 终止与证书管理深入
HTTPS 流量处理涉及三个独立的 TLS 配置点,理清它们的边界是正确配置 HTTPS 入口的基础。
第一段:客户端到 Ingress/Gateway Controller(frontend TLS)。由 Ingress 的 tls 字段或 Gateway listener 的 tls 字段配置,指定证书 Secret。Controller 在监听端口(443)上终止 TLS,把明文 HTTP 发给后端——这是标准的 TLS offloading 模式,适合后端是普通 HTTP 服务的场景。
第二段:Controller 到后端 Service(backend TLS / re-encryption)。如果后端 Service 也要求 HTTPS(如要求端到端加密的合规场景),Ingress Controller 需要配置"二次加密":从外部客户端处终止 TLS,再用一套(可能不同的)证书与后端重新建立 TLS 连接。Nginx Ingress 用 nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" annotation 实现,Gateway API 用 BackendTLSPolicy 指定后端的 CA 证书和 SNI。
第三段:mTLS(双向 TLS)。不仅客户端验证服务器证书,服务器也要验证客户端证书。在零信任架构里,每个服务都有自己的客户端证书(通常由集群内的 CA 签发,如 cert-manager + HashiCorp Vault),通过 mTLS 实现服务间身份验证,不需要应用层的 token 或 API Key。Nginx Ingress 支持在外部请求层面做 mTLS(nginx.ingress.kubernetes.io/auth-tls-secret),Gateway API 的 BackendTLSPolicy 支持 controller 到后端的 mTLS。
cert-manager 是证书生命周期管理的事实标准,它的工作方式值得细看:创建 Certificate 对象(描述证书的域名、颁发者、存储位置),cert-manager 的 controller 向对应的 Issuer/ClusterIssuer 请求签发,把签发结果写入指定 Secret,在证书到期前自动触发续期。Ingress 和 Gateway 直接引用这个 Secret,不需要感知证书的生命周期管理。
Let’s Encrypt 的证书有效期 90 天,cert-manager 默认在到期前 30 天开始续期。续期方式有两种:HTTP-01(cert-manager 在集群里临时创建一个 Service,Let’s Encrypt 通过 HTTP 访问 /.well-known/acme-challenge/<token> 验证域名所有权,要求域名能被 Let’s Encrypt 的服务器访问)和 DNS-01(cert-manager 在 DNS 提供商的区域里创建一条 TXT 记录,Let’s Encrypt 通过 DNS 查询验证,不需要 HTTP 访问,适合内部域名或通配符证书)。
Gateway API 在 cert-manager 1.15+ 之后获得了原生支持:在 Gateway 上标注 cert-manager.io/cluster-issuer: letsencrypt-prod,cert-manager 自动为 listeners 里每个 HTTPS 端口签发证书并写入对应 Secret,不再需要手动创建 Certificate 对象。这是 cert-manager 与 Gateway API 的深度集成,比 Ingress annotation 模式更声明式。
证书轮换期间,cert-manager 先签发新证书写入 Secret,Controller 检测到 Secret 更新后热加载新证书,整个过程对客户端无感知(TLS 会话复用不受影响,新建连接使用新证书)。通配符证书(*.example.com)必须用 DNS-01 验证,一张证书可以覆盖同域名下的所有子域 Ingress/HTTPRoute,比为每个子域单独申请证书更经济。
Gateway API 的 ReferenceGrant 解决了跨命名空间引用的安全问题。在没有 ReferenceGrant 的情况下,HTTPRoute 不能引用其他命名空间里的 Service,防止租户 A 绕过权限把流量路由到租户 B 的 Service。ReferenceGrant 由被引用资源所在命名空间的管理员创建,明确声明允许哪个命名空间的哪类资源引用本命名空间里的哪类资源——这是 Gateway API 在多租户场景下优于 Ingress 的关键安全设计。实际部署中,平台团队维护 Gateway 和 ReferenceGrant,应用团队维护 HTTPRoute,职责边界清晰,不需要依赖 annotation 或 RBAC 的间接约束。
Gateway API 的演进路线值得关注。GRPCRoute 在 1.28 升为 GA,TCPRoute 和 TLSRoute 仍处于实验性阶段(需要安装实验性 CRD),UDPRoute 目前支持的 Controller 较少。SIG Network 正在推进 HTTPRoute 的 retry/timeout 字段标准化(目前部分 Controller 通过 Policy Attachment 实现,尚未进入核心 spec)。随着 Gateway API 日趋成熟,Ingress 的开发已进入维护模式——Kubernetes 不计划为 Ingress spec 增加新功能,新功能统一在 Gateway API 里实现。对于新项目,直接采用 Gateway API 是更有长期价值的选择。
从 Ingress 迁移到 Gateway API 的实际路径:先确认所用 Ingress Controller 是否提供 Gateway API 实现(Nginx、Traefik、Envoy Gateway、Cilium 均已支持),再按命名空间逐步迁移——先创建等价的 HTTPRoute,用流量镜像(RequestMirror filter)验证新旧路径行为一致,再切换 DNS 或云 LB 指向新 Gateway,最后下线旧 Ingress 对象。整个过程可以做到零停机,因为 Ingress 和 HTTPRoute 可以在同一集群里并存,指向不同的 Controller 实例。
系列导航
- 00 核心概念导读
- 01 API Server 与声明式 API
- 02 etcd 与持久化
- 03 控制器模式与 Informer 机制
- 04 Pod 生命周期
- 05 调度器深入
- 06 kubelet 与容器运行时
- 07 网络模型与 CNI
- 08 Service 与 kube-proxy
- 09 Ingress 与 Gateway API
- 10 存储体系
- 11 配置与密钥管理
- 12 RBAC 与安全模型
- 13 资源管理与自动伸缩
- 14 CRD 与 Operator 模式
- 15 Helm 与应用打包
- 16 可观测性
- 17 生产集群运维
参考资料
- Kubernetes Ingress — Ingress 对象规范,包含 rules、tls、ingressClassName 的完整字段定义
- Gateway API — SIG Network 维护的 Gateway API 规范站,包含 GatewayClass/Gateway/HTTPRoute/GRPCRoute 的完整定义
- Gateway API Concepts — Gateway API 三层角色模型和与 Ingress 的对比分析
- Nginx Ingress Controller — Nginx Ingress Controller 官方文档,包含所有支持 annotation 的完整列表
- Envoy Gateway — 基于 Envoy 的 Gateway API 参考实现,支持完整的 HTTPRoute 规范
- Gateway API v1.0 GA Blog — Kubernetes 官方博客关于 Gateway API 1.0 GA 的发布说明,包含设计决策背景
