第27章 Ingress 与南北流量:Ingress-nginx 与 Gateway API

学习目标

  • 分清南北流量与东西流量,理解 Ingress 管的是"入口"
  • 看清 Ingress = 规则(API 对象)+ Ingress Controller(真正干活的反向代理)
  • 走通流量路径:client → LB/NodePort → Controller → 后端 Pod
  • 理解 Ingress 的局限与 Gateway API 新标准

前置知识


原理

南北 vs 东西流量

  南北流量(North-South):集群外 ←→ 集群内    ← Ingress 管这个
       用户 → [Ingress] → 集群内服务

  东西流量(East-West):服务 ←→ 服务(集群内部)  ← Service Mesh 管这个(第26/29章)
       服务A → 服务B

本章讲南北入口:外部请求如何进入集群。

Ingress = 规则 + Controller(关键认知)

很多人以为 Ingress 是个代理——不是。Ingress 是两部分:

① Ingress 资源(K8s API 对象)= 一份"路由规则声明"
     host/path → Service,仅仅是声明,自己不转发任何流量

② Ingress Controller = 真正的反向代理(Nginx/Envoy/HAProxy/Traefik)
     它 watch K8s API,把 Ingress 规则翻译成自己的配置,真正接流量、转发

Ingress 资源是"想要什么",Ingress Controller 是"怎么实现"。 只创建 Ingress 资源而没装 Controller,啥也不会发生——这是新手头号困惑。

Ingress Controller 的工作原理

以 ingress-nginx 为例(k8sLab 第14课):

  ingress-nginx Pod 内:
    [controller 进程] watch K8s API(Ingress/Service/Endpoints 变化)
          │ 变化时
          ▼ 生成/更新 nginx.conf(host/path → upstream)
    [nginx 反向代理] 按配置接流量、转发到后端 Pod
  • 路由规则变 → 重新生成 nginx.conf → reload
  • Endpoints 变(Pod 扩缩容) → ingress-nginx 用 Lua 动态更新 upstream,避免频繁 reload(呼应 第13章 OpenResty)

流量路径全景

  外部 Client
     │
     ▼ ① 经云 LB(type=LoadBalancer)或 NodePort 进集群
  [ingress-nginx Service]
     │
     ▼ ② 到 ingress-nginx Controller Pod(反向代理)
  [Controller: 按 host/path 选后端]
     │
     ▼ ③ 直接转发到后端 Pod IP(通常跳过 ClusterIP/kube-proxy,直连 Endpoints)
  [业务 Pod]

注意③:ingress-nginx 通常从 Endpoints 拿到 Pod IP 直连,绕过 Service 的 ClusterIP(kube-proxy),减少一跳、负载更均(呼应 第09章连接级 LB)。

Ingress 资源示例

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /     # 高级功能靠 annotation(各家不通用!)
spec:
  ingressClassName: nginx                              # 指定哪个 Controller 处理
  tls:
  - hosts: [app.example.com]
    secretName: app-tls                                # TLS 终止用的证书(第05章)
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /api
        pathType: Prefix
        backend: { service: { name: api-svc, port: { number: 80 } } }
      - path: /
        pathType: Prefix
        backend: { service: { name: web-svc, port: { number: 80 } } }

Ingress 的局限 → Gateway API

Ingress 资源表达力很弱:只有 host/path,其它高级能力(重写、灰度、限流、mTLS)全靠 annotation,而 annotation 各家 Controller 不通用——换个 Controller 就得重写。

Gateway API 是 K8s 新的入口标准,解决这些痛点:

IngressGateway API
表达力弱(host/path + annotation)强(原生支持流量切分、Header 匹配、跨命名空间等)
可移植差(annotation 各家不同)好(厂商中立的 CRD)
角色分离无有(GatewayClass/Gateway/Route 分给不同角色)
协议主要 HTTPHTTPRoute/TLSRoute/GRPCRoute/TCPRoute

Gateway API 的三层对象:

  GatewayClass(厂商实现,集群级,类似 IngressClass)
     └─ Gateway(监听器:端口/协议/证书,平台运维管)
          └─ HTTPRoute(路由规则:host/path/header→Service,应用开发管)

这种角色分离(基础设施 / 平台 / 应用各管一层)是 Gateway API 的核心理念,也是 Service Mesh 与 Ingress 走向统一的方向(第29章)。


️ 实现 / 命令

实验一:装 Controller + 创建 Ingress

# 装 ingress-nginx
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/baremetal/deploy.yaml
kubectl apply -f web-ingress.yaml

# 访问验证(Host 头要匹配 rule)
curl -H "Host: app.example.com" http://<node-ip>:<nodeport>/api

实验二:看 Controller 生成的 nginx.conf

# Ingress 规则被翻译成了真实的 nginx 配置
kubectl exec -n ingress-nginx <controller-pod> -- cat /etc/nginx/nginx.conf | grep -A5 "app.example.com"
# server { server_name app.example.com; location /api { ... proxy_pass ... } }

亲眼看到你的 Ingress YAML 变成了 第13章 的 nginx server/location——Ingress Controller 就是个被 K8s 驱动的 Nginx。

实验三:Gateway API(新标准)

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata: { name: prod-gw }
spec:
  gatewayClassName: nginx
  listeners:
  - { name: http, protocol: HTTP, port: 80 }
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: { name: web-route }
spec:
  parentRefs: [{ name: prod-gw }]
  hostnames: ["app.example.com"]
  rules:
  - matches: [{ path: { type: PathPrefix, value: /api } }]
    backendRefs: [{ name: api-svc, port: 80 }]

排错

现象根因解决
创建 Ingress 没反应没装 Controller装 ingress-nginx 等
404 default backendhost/path 不匹配核对 Host 头、pathType
多个 Controller 抢没指定 ingressClassName显式设 ingressClassName
TLS 不生效secretName 证书缺失/错检查 secret(第05章)
annotation 不生效换了 Controller,annotation 不通用用对应 Controller 的 annotation,或迁 Gateway API
外部访问不到LB/NodePort 没暴露检查 ingress-nginx Service 类型

本章小结

  • 南北流量靠 Ingress(入口),东西流量靠 Mesh(第26/29章)。
  • Ingress = 规则(API 对象)+ Controller(真正的反向代理);只建规则不装 Controller 无效。
  • ingress-nginx 把 Ingress 规则翻译成 nginx.conf,Endpoints 变化用 Lua 动态更新;通常直连 Pod IP。
  • Ingress 表达力弱、annotation 不通用 → Gateway API(角色分离、厂商中立、多协议)是新方向。

下一章 第28章 Egress 出网治理,把方向反过来:集群内的 Pod 如何安全、可控、可审计地访问外部世界——这是企业 K8s 落地的安全刚需。