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 是否成功。
二、数据平面选型:Nginx、Traefik、HAProxy 的取舍
控制器负责“翻译”,数据平面负责“转发”。选型时真正要比较的是:配置模型是否匹配你的路由复杂度、动态更新能力、可观测性、以及团队是否熟悉其配置语言。
| 维度 | Nginx Ingress | Traefik | HAProxy 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 会把正常节点摘除。
status.loadBalancer.ingress 出现,或对入口做一次健康探测,再放量。把这三层串起来看:控制器是“翻译官”,数据平面是“执行者”,部署模式与高可用是“让执行者始终在线”的工程保障。理解监听与调谐的时序、选型时的真实取舍、以及高可用验证的判据,才能在 Ingress 不生效、503 频发或节点故障时快速定位到具体环节。