3. Ingress Controller 工作原理

Ingress 资源本身只是一份声明式的路由规则,它不会自己产生任何流量处理能力。真正把 Ingress 对象翻译成“某个进程正在监听 80/443 端口、按 Host 和 Path 转发到后端 Service”的,是 Ingress Controller。理解它的工作原理,核心是理解两件事:控制平面如何“监听—调谐”,数据平面由谁承担转发。

一、监听与调谐循环:控制器的“大脑”

Ingress Controller 通常以 Pod 形式运行在集群内,它同时扮演两个角色:一是 Kubernetes API 的客户端(控制平面),二是反向代理进程的管理者(数据平面)。其工作循环可以概括为“Watch → 计算期望状态 → 生成配置 → 重载数据平面 → 回写状态”。

以最常见的 Nginx Ingress Controller 为例,启动后会做几件事:通过 Informer 机制对 Ingress、Service、Endpoints/EndpointSlice、Secret、ConfigMap 等资源建立长连接 Watch。当这些对象发生增删改时,事件进入本地缓存(DeltaFIFO + Indexer),控制器并不需要轮询 API Server,而是由事件驱动触发调谐。

调谐时,控制器把当前集群中所有 Ingress 规则、对应 Service 的 ClusterIP、以及 Endpoints 里的 Pod IP:Port 汇总,计算出一份“期望的 Nginx 配置”。这份配置随后被渲染成 nginx.conf,写入容器内的临时文件,再通过 nginx -s reload 或向 Nginx 进程发送信号使其平滑加载。重载完成后,控制器会通过 Ingress 对象的 status.loadBalancer.ingress 字段回写实际入口地址(例如云 LB 的 IP 或域名),这样 kubectl get ingress 才能看到 ADDRESS。

这里有一个关键点:调谐是“最终一致”而非“实时”。从 Ingress 被创建,到 Nginx 真正生效,中间存在事件传播、配置渲染、reload 三个阶段的延迟,通常在百毫秒到数秒量级。如果 Endpoints 尚未就绪(Pod 未 Ready),控制器会生成一个没有可用后端的 upstream,此时请求会返回 503。因此排查“Ingress 不生效”时,顺序应是:Ingress 是否被控制器识别 → Service 是否有 Endpoints → Nginx 配置是否已包含该 server 块 → reload 是否成功。

Ingress Controller 监听与调谐循环 Kubernetes API Server Ingress / Service Endpoints / Secret ConfigMap Watch 事件 Ingress Controller Informer 本地缓存 计算期望配置 渲染 nginx.conf 触发 reload reload 数据平面 Nginx / Traefik HAProxy 监听 80 / 443 转发到 Pod 回写 status.loadBalancer 后端 Service → Pod Endpoints 未就绪 → 503 调谐延迟的三个阶段 事件传播:API Server → Informer 缓存 配置渲染:汇总规则生成 nginx.conf 平滑重载:nginx -s reload 生效

二、数据平面选型:Nginx、Traefik、HAProxy 的取舍

控制器负责“翻译”,数据平面负责“转发”。选型时真正要比较的是:配置模型是否匹配你的路由复杂度、动态更新能力、可观测性、以及团队是否熟悉其配置语言。

维度Nginx IngressTraefikHAProxy Ingress
配置模型注解(annotations)驱动,生态最广CRD(IngressRoute/Middleware)原生注解 + 部分 CRD
动态更新reload 或 Lua/OpenResty 热更新无需 reload,事件驱动热加载支持 runtime API 动态更新
典型优势成熟稳定、资料多、性能可预期自动 HTTPS、中间件链清晰高并发、负载均衡算法丰富
适用场景通用生产入口、注解生态依赖强多租户、频繁变更、边缘路由大流量、对 L4/L7 性能敏感

需要强调的是,选型不是“谁更好”,而是“谁更匹配”。如果团队已有大量 Nginx 运维经验,Nginx Ingress 的注解体系能直接复用;如果希望路由规则以 CRD 形式版本化管理、并需要自动证书与中间件组合,Traefik 的表达更自然;如果入口需要承载数十万并发连接、且对健康检查与负载算法有精细要求,HAProxy 的数据平面更合适。

三、部署模式与高可用

Ingress Controller 的部署模式决定了入口的可用性与流量路径。常见有三种:

  • Deployment + NodePort:控制器以 Deployment 部署,Service 类型为 NodePort,外部通过节点 IP:NodePort 访问。实现简单,但端口固定、节点故障需外部 LB 兜底。
  • Deployment + LoadBalancer:在云环境中由云厂商分配 LB,流量经 LB 打到控制器 Pod。适合云上,但 LB 本身可能成为单点,需要多可用区。
  • DaemonSet + hostNetwork:每个节点跑一个控制器 Pod,直接占用宿主机 80/443。配合外部 LB 或 BGP/ECMP 做多节点入口,延迟低、无额外转发跳数,是自建高可用入口的常见选择。

高可用的关键不在“多副本”本身,而在于:入口层要有多个可达节点,且控制器副本要分散到不同节点/可用区。以 DaemonSet 模式为例,通常配合 nodeSelector 或 taint/toleration 把控制器调度到专用边缘节点,再用外部 LB 将 VIP 漂移到这些节点。控制器副本之间通过 Leader Election 选主,只有 Leader 负责写 status,避免多副本同时回写造成冲突。

# 以 DaemonSet + hostNetwork 为例的关键片段
spec:
  template:
    spec:
      hostNetwork: true
      dnsPolicy: ClusterFirstWithHostNet
      nodeSelector:
        ingress-ready: "true"
      tolerations:
      - key: node-role.kubernetes.io/edge
        operator: Exists
        effect: NoSchedule
      containers:
      - name: controller
        image: registry.k8s.io/ingress-nginx/controller:v1.11.0
        args:
        - /nginx-ingress-controller
        - --publish-service=$(POD_NAMESPACE)/ingress-nginx-controller
        - --election-id=ingress-nginx-leader
        - --update-status=true

验证高可用是否真正生效,不能只看 Pod 是否 Running。应做三件事:一是 kubectl get pods -o wide 确认副本分布在不同节点;二是模拟一个节点宕机(cordon + drain 或直接关机),观察入口流量是否在秒级内切到其他节点;三是检查 kubectl get ingress 的 ADDRESS 是否仍指向可用入口。若使用云 LB,还要确认健康检查路径(通常是 /healthz)返回 200,否则 LB 会把正常节点摘除。

调谐循环的“最终一致”意味着:Ingress 创建后立即压测可能命中 503。工程上应在发布流程中等待 status.loadBalancer.ingress 出现,或对入口做一次健康探测,再放量。
多副本控制器必须开启 Leader Election。若关闭,多个副本会同时渲染配置并 reload,虽然多数情况下结果一致,但在规则频繁变更时可能出现配置抖动与 status 冲突。

把这三层串起来看:控制器是“翻译官”,数据平面是“执行者”,部署模式与高可用是“让执行者始终在线”的工程保障。理解监听与调谐的时序、选型时的真实取舍、以及高可用验证的判据,才能在 Ingress 不生效、503 频发或节点故障时快速定位到具体环节。