Skip to content

Kubernetes Ingress、TLS与七层流量排障

Ingress 是 Kubernetes 中描述 HTTP/HTTPS 路由的 API 对象,但 Ingress 对象本身不监听端口、不终止 TLS、也不转发任何请求。真正读取规则并运行代理数据面的,是 NGINX Ingress Controller、HAProxy Ingress、Traefik、云厂商 ALB Controller 等具体 Controller。

本页从浏览器输入域名开始,追踪外部DNS、云负载均衡器、Controller Service、Ingress Controller Pod、IngressClass、TLS Secret、Service、EndpointSlice和业务Pod。重点回答:为什么 YAML 已创建但没有流量、404 是哪一层返回、502/503/504怎样区分、证书更新为何未生效、Path重写为何会改变应用路由。

学习目标

学完后应能:

  1. 区分 Ingress、IngressClass、Ingress Controller、Controller Service和外部LB。
  2. 解释创建 Ingress 对象后 Controller 如何 Reconcile 成真实代理配置。
  3. 从公网DNS追踪到业务Pod,并指出每一跳的证据。
  4. 区分 Host、SNI、Path、PathType、Backend Service和EndpointSlice。
  5. 解释 Exact、Prefix、ImplementationSpecific匹配边界。
  6. 解释 TLS握手、Secret、证书链、SAN、私钥和终止位置。
  7. 区分 TLS Termination、Re-encryption和Passthrough的实现边界。
  8. 说明 Rewrite、超时、请求体、重试、WebSocket和gRPC为什么依赖Controller。
  9. 正确处理 X-Forwarded-For、可信代理和客户端源IP。
  10. 根据404、502、503、504、413、TLS错误和重定向循环定位故障层。
  11. 设计生产入口的权限、隔离、可观测性、灰度和回滚。
  12. 区分 Kubernetes Gateway API 与 Spring Cloud Gateway等业务网关。

一、Ingress不等于Ingress Controller

对象形态主要职责
IngressKubernetes API对象声明Host、Path、TLS和Backend
IngressClassKubernetes API对象指定哪类Controller处理Ingress
Ingress Controller控制器进程Watch对象、校验并生成代理配置
Controller Pod工作负载实例真正监听80/443并代理请求
Controller ServiceService对象把流量送到Controller Pod
外部LoadBalancer云/机房资源把公网或专网流量送入集群入口

只创建 Ingress 而集群没有匹配的 Controller,结果通常是:

  • API Server接受对象。
  • kubectl get ingress能看到规则。
  • 没有代理进程读取和执行。
  • Status可能没有地址。
  • 外部请求无法按规则转发。

这和“写了一份Nginx配置文件但没有启动Nginx”类似。

二、从公网域名到业务Pod的完整路径

一种常见云上路径:

mermaid
flowchart TD
    A["浏览器解析api.example.com"] --> B["公网DNS返回LoadBalancer地址"]
    B --> C["客户端与外部LB建立TCP/TLS连接"]
    C --> D["LB转发到Ingress Controller Service"]
    D --> E["Service数据面选择Controller Pod"]
    E --> F["Controller按SNI、Host和Path匹配规则"]
    F --> G["Controller选择Backend Service/Endpoint"]
    G --> H["请求到达业务Pod targetPort"]
    H --> I["响应沿连接返回客户端"]

具体实现可能不同:

  • LB → NodePort → Controller Pod。
  • LB直接使用Pod/ENI后端。
  • Controller以DaemonSet运行并使用HostNetwork。
  • 云ALB本身就是数据面,Controller只配置云资源。
  • Controller直接代理到EndpointSlice中的PodIP,而不再访问Service ClusterIP。

排查前先画出目标集群真实路径,不能把某个发行版的数据流当成所有环境通用结构。

三、Ingress Controller的Reconcile全过程

典型 Controller 会观察:

  • IngressClass。
  • Ingress。
  • Service。
  • EndpointSlice。
  • TLS Secret。
  • Controller ConfigMap/自定义资源。
  • Namespace和相关引用对象。
mermaid
flowchart TD
    A["API对象发生Add/Update/Delete"] --> B["Informer更新本地缓存并入队"]
    B --> C["Controller读取相关Ingress/Class/Service/Secret"]
    C --> D["校验Host、Path、Backend和证书引用"]
    D --> E["构建期望代理模型"]
    E --> F["生成配置或调用云API"]
    F --> G{"配置是否有效"}
    G -- "否" --> H["保留安全配置并记录Event/日志"]
    G -- "是" --> I["热更新、动态配置或reload数据面"]
    I --> J["更新Ingress Status和指标"]

3.1 为什么对象更新不是瞬间生效

从 API 持久化到数据面生效,需要经历 Watch、队列、Reconcile、配置校验、代理更新和多副本传播。短时间看到新旧行为并存可能是传播过程,也可能是部分 Controller Pod 更新失败。

3.2 Controller为什么要监听Service、EndpointSlice和Secret

Ingress规则引用Service,但后端Pod和证书会独立变化:

  • Pod滚动更新导致EndpointSlice变化。
  • Service端口修改影响后端解析。
  • TLS Secret轮换影响证书。
  • Controller配置修改影响全局超时或安全策略。

只Watch Ingress本身无法保持实际代理配置最新。

3.3 Reload与动态更新

不同Controller可能:

  • 生成配置并优雅Reload。
  • 通过共享内存/运行时API动态更新后端。
  • 调用云厂商API配置外部ALB。

Reload失败时应保留上一份可用配置并告警;不能让一个错误Ingress拖垮所有租户入口。确切隔离能力取决于实现。

四、IngressClass决定谁处理规则

示例:

yaml
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  name: public-nginx
spec:
  controller: k8s.io/ingress-nginx

应用Ingress引用:

yaml
spec:
  ingressClassName: public-nginx

spec.controller 是Controller标识,不是Deployment名称。平台团队通常创建IngressClass,业务团队引用;业务项目不应各自创建同名集群级Class。

4.1 多Controller场景

企业集群可能同时有:

  • 公网入口。
  • 内网入口。
  • PCI/医疗隔离入口。
  • 不同云ALB类型。

每个Controller只处理匹配Class的Ingress。Class错了可能出现:

  • 没有Controller接管。
  • 被错误的公网Controller暴露。
  • Status地址来自错误入口。
  • Controller专有Annotation被忽略。

4.2 默认IngressClass

平台可以标记一个默认Class,使未写 ingressClassName 的Ingress被默认处理。多个Class同时声明默认会造成创建/归属问题。生产建议业务清单显式指定Class,避免集群默认值变化后入口漂移。

4.3 旧Annotation边界

旧清单常见:

yaml
kubernetes.io/ingress.class: nginx

现代API优先使用 spec.ingressClassName。旧Annotation是否兼容取决于Controller版本,迁移时检查Release Notes,不要同时写冲突值。

五、Ingress对象结构

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: order-api
  namespace: commerce
spec:
  ingressClassName: public-nginx
  tls:
    - hosts:
        - api.example.com
      secretName: api-example-com-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: order-api
                port:
                  name: http

约束:

  • Ingress和Backend Service通常必须在同一Namespace,跨Namespace后端需使用其他受支持API/机制。
  • TLS Secret通常也在Ingress同一Namespace。
  • Service端口引用必须存在。
  • host是HTTP Host匹配条件,不负责创建公网DNS。
  • status.loadBalancer地址由Controller更新,不等于DNS自动指向它。

六、外部DNS为什么不是Ingress自动创建的

Ingress写了:

yaml
host: api.example.com

只表示请求的 Host 匹配规则。仍需:

  1. Controller入口有可达的IP/域名。
  2. DNS平台创建A/AAAA/CNAME记录。
  3. 记录指向正确环境入口。
  4. TTL与切换策略满足发布要求。

有些集群安装 ExternalDNS等Controller自动同步DNS,但那是额外组件和权限,不是Ingress API内置保证。DNS错误可能把生产域名指向测试入口,即使Ingress YAML完全正确。

七、Host匹配

客户端HTTP请求携带:

http
Host: api.example.com

Controller按Host选择Virtual Host。测试时不能只访问IP:

bash
curl -vk https://203.0.113.10/orders

这可能发送错误Host并命中默认后端。应使用:

bash
curl -vk --resolve api.example.com:443:203.0.113.10 \
  https://api.example.com/orders

--resolve同时让URL Host、TLS SNI和连接IP保持正确,适合绕过尚未切换的DNS测试入口。

7.1 无Host规则

不写Host的规则可能匹配到达该入口的多个Host,容易扩大暴露面。生产公网入口优先显式Host,并配置安全默认后端。

7.2 通配符Host

Ingress支持的通配符语义受API规则约束,通常只匹配单层子域,例如:

text
*.example.com

不要假设它匹配任意多层。证书SAN也必须覆盖对应域名。

八、PathType三种语义

8.1 Exact

yaml
path: /orders
pathType: Exact

精确匹配 /orders,通常不匹配 /orders/123

8.2 Prefix

yaml
path: /orders
pathType: Prefix

/ 分隔的路径元素匹配,通常匹配:

text
/orders
/orders/
/orders/123

但不应把简单字符串前缀误认为一定匹配 /orders-old

8.3 ImplementationSpecific

含义由IngressClass/Controller决定,可能支持正则或控制器特有规则。它降低可移植性,升级或更换Controller时必须重新验证。

九、多个Path如何选择

当多个规则都匹配时,Kubernetes Ingress规范倾向最长匹配路径;路径长度相同时,Exact通常优先于Prefix。Controller仍可能有实现细节和Annotation影响。

示例:

yaml
paths:
  - path: /api/orders
    pathType: Prefix
    backend:
      service:
        name: order-api
        port:
          name: http
  - path: /api
    pathType: Prefix
    backend:
      service:
        name: api-gateway
        port:
          name: http
  - path: /
    pathType: Prefix
    backend:
      service:
        name: web
        port:
          name: http

/api/orders/1应优先进入更长的 /api/orders,而不是只按YAML书写顺序。

9.1 多个Ingress声明同一Host和Path

不同团队可能在不同Ingress对象中同时声明 api.example.com/orders。Ingress API没有定义一个适用于所有Controller的“后创建覆盖先创建”规则;有的实现合并,有的拒绝,有的按内部顺序选择,并可能在升级后变化。

平台必须在Admission阶段校验Host/Path所有权,或按团队分配独立域名/Class。不能把共享生产域名冲突交给Controller碰运气。

十、默认后端和404来源

请求没有匹配任何Host/Path时,Controller通常交给默认后端或自身返回404。404可能来自三层:

  1. 外部CDN/LB/WAF。
  2. Ingress Controller默认后端或未匹配规则。
  3. 业务应用自身路由。

区分方法:

  • 查看响应Header、Server标识和Request ID。
  • 查看Controller Access Log是否有请求和上游信息。
  • 查看业务Pod日志是否收到请求。
  • 使用正确Host/SNI直接测试入口。

如果Controller日志有404且没有上游,优先查Host/Path/Class;如果上游返回404且业务日志有请求,查应用Context Path和Rewrite。

Ingress资源也可声明自己的默认后端:

yaml
spec:
  defaultBackend:
    service:
      name: safe-default-backend
      port:
        name: http

它用于该Ingress没有规则匹配时的默认服务。Controller还可能配置全局默认后端,两者优先和合并行为需要按实现验证。默认后端应返回最小安全响应,不泄露内部Host、代理版本、集群路径或调试信息。

十一、Rewrite不是Ingress通用字段

标准Ingress描述匹配和Backend,不定义所有控制器的路径重写语义。NGINX Ingress等实现通过Annotation提供Rewrite。

示意(仅适用于对应Controller和版本):

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/use-regex: "true"
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: public-nginx
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /api(/|$)(.*)
            pathType: ImplementationSpecific
            backend:
              service:
                name: order-api
                port:
                  name: http

请求:

text
/api/orders/1

重写后可能发送:

text
/orders/1

常见错误:

  • 应用本来就期望 /api/orders,又被重写掉 /api
  • 捕获组编号错误。
  • Controller升级后正则行为变化。
  • 多个Ingress合并后Annotation影响范围超出预期。

生产应为原始URL、重写后URL和应用Route建立自动化测试。

十二、Ingress到Service还是直接到Endpoint

Ingress Backend在API中引用Service,但Controller数据面可能:

  • 代理到Service ClusterIP。
  • 读取EndpointSlice并直接代理到Pod IP。
  • 调用云API把Pod/Node注册为LB后端。

因此“Service ClusterIP从Controller Pod可访问”是一个证据,但不一定完全等于实际Controller后端路径。要查看Controller生成配置、上游地址或云LB Target Group。

直接Endpoint模式的优点可能是减少一层转发并获得后端健康信息;代价是Controller必须及时跟踪Endpoint变化。

十三、TLS握手全过程

典型TLS在Ingress Controller终止:

mermaid
flowchart TD
    A["客户端解析域名并连接443"] --> B["发送ClientHello和SNI"]
    B --> C["入口根据SNI选择证书"]
    C --> D["返回服务端证书链和握手参数"]
    D --> E["客户端校验证书SAN、有效期、签发链"]
    E --> F["协商会话密钥并完成TLS"]
    F --> G["客户端发送带Host的HTTP请求"]
    G --> H["Controller匹配Ingress并代理后端"]

SNI在TLS握手阶段选择证书,HTTP Host在握手后选择HTTP路由。两者通常相同,但它们处于不同协议阶段。

十四、TLS Secret结构和安全

创建:

bash
kubectl create secret tls api-example-com-tls -n commerce \
  --cert=fullchain.pem \
  --key=private-key.pem \
  --dry-run=client -o yaml

典型Secret:

yaml
apiVersion: v1
kind: Secret
metadata:
  name: api-example-com-tls
  namespace: commerce
type: kubernetes.io/tls
data:
  tls.crt: <base64-full-chain>
  tls.key: <base64-private-key>

Base64不是加密。私钥保护依赖:

  • RBAC最小权限。
  • etcd静态加密。
  • Secret管理/外部KMS。
  • Controller和Node权限。
  • 审计和轮换。

不要把真实私钥提交到Git。GitOps可使用加密Secret、External Secrets或证书Controller等受控方案。

十五、证书必须验证哪些内容

bash
openssl s_client -connect api.example.com:443 \
  -servername api.example.com -showcerts

检查:

  • Subject Alternative Name包含域名。
  • Not Before/Not After有效。
  • 中间证书链完整。
  • 私钥与证书公钥匹配。
  • Controller实际返回的是新证书而非默认/旧证书。
  • 客户端信任根证书。
  • SNI正确。

只看Secret更新时间不能证明Controller已经加载;要从真实入口握手验证。

十六、TLS终止、重加密和透传

16.1 TLS Termination

text
Client --HTTPS--> Ingress Controller --HTTP--> Backend

入口解密,便于七层路由、WAF和指标。Controller到Pod之间未加密,需要可信内网、NetworkPolicy或其他加密措施。

16.2 Re-encryption

text
Client --HTTPS--> Controller --HTTPS--> Backend

Controller终止客户端TLS,再以独立TLS连接后端,需要验证后端证书、SNI和CA。具体Annotation/CRD由Controller决定。

16.3 TLS Passthrough

text
Client --TLS--> Controller/LB --TLS--> Backend

入口不解密,通常只能依据SNI做有限四层/五层选择,无法读取HTTP Path和Header。标准Ingress支持程度有限,属于Controller特有能力。

三者不能只凭“端口是443”判断,应查看Controller配置和抓取握手证据。

十七、证书自动化和cert-manager边界

cert-manager等Controller可根据Certificate/Issuer资源申请并续期证书,再更新Secret。完整链路包括:

text
Certificate声明
→ Issuer/ClusterIssuer
→ ACME或企业CA验证
→ 签发证书
→ 写入TLS Secret
→ Ingress Controller观察Secret
→ 热加载证书
→ 真实握手验证

任一步失败都会造成续期风险。监控应关注证书剩余时间、Certificate Condition、Challenge、Secret版本和真实入口证书,不能只监控其中一个对象。

十八、HTTP到HTTPS重定向

常见入口把80重定向到443。重定向可能在:

  • 外部CDN/LB。
  • Ingress Controller。
  • Spring Cloud Gateway。
  • 业务应用。

多个层都强制且不正确信任 X-Forwarded-Proto 时,可能产生循环:

text
Client HTTPS
→ LB终止TLS并用HTTP访问Controller/应用
→ 应用认为当前是HTTP并重定向HTTPS
→ Client再次HTTPS
→ 循环

应明确TLS终止点,并只信任来自已知代理的Forwarded Header。

十九、客户端源IP和Forwarded Header

经过多层代理后,后端TCP源IP通常是Controller Pod/Node,而不是用户。常用Header:

http
Forwarded: for=203.0.113.9;proto=https;host=api.example.com
X-Forwarded-For: 203.0.113.9, 10.0.1.10
X-Forwarded-Proto: https
X-Forwarded-Host: api.example.com
X-Request-ID: ...

不能无条件相信客户端自己传来的 X-Forwarded-For。正确治理:

  1. 外层可信LB覆盖或规范追加Header。
  2. Controller只信任配置的代理CIDR。
  3. 应用框架只在请求来自可信代理时解析Forwarded Header。
  4. 日志同时记录连接源、解析后的客户端IP和代理链。
  5. 限流与审计使用经过信任边界处理的地址。

否则攻击者可以伪造IP绕过限流或污染审计。

二十、Controller直接暴露还是经过LoadBalancer

常见Controller Service:

yaml
apiVersion: v1
kind: Service
metadata:
  name: ingress-public-controller
  namespace: ingress-system
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  selector:
    app: ingress-public-controller
  ports:
    - name: http
      port: 80
      targetPort: http
    - name: https
      port: 443
      targetPort: https

externalTrafficPolicy: Local常用于保留源IP,但要求外部LB只把流量送到有本地Controller Pod的Node。Controller Deployment的拓扑分布、PDB、Readiness和节点容量都会影响入口可用性。

应用团队通常不维护Controller Service,这属于平台层资源;页面示例用于理解链路。

二十一、请求体大小限制

文件上传收到413通常是入口限制,不一定到达业务Pod。NGINX Ingress示意:

yaml
metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "20m"

这是Controller专有Annotation。还要检查:

  • CDN/WAF/LB限制。
  • Controller全局限制。
  • Spring Boot/Servlet multipart限制。
  • Gateway限制。
  • 业务安全和存储容量。

不要只把限制无限调大;大型文件应考虑对象存储直传、分片、病毒扫描和配额。

二十二、超时不是一个参数

入口可能涉及:

  • 客户端连接超时。
  • TLS握手超时。
  • Controller连接Backend超时。
  • 发送请求到Backend超时。
  • 等待响应头超时。
  • 读取响应超时。
  • 写回客户端超时。
  • 外部LB Idle Timeout。
  • 应用和下游超时。

Controller Annotation名称和单位依实现而异。必须遵循超时预算:

text
客户端总超时
> 入口处理与重试预算
> 应用自身总预算
> 单次下游调用超时

如果外层30秒、应用60秒,入口会先返回504,但应用可能继续执行并产生副作用,客户端重试又可能重复下单。

二十三、502、503和504不能只靠状态码猜

不同Controller定义可能不同,通用方向:

  • 502:连接后端失败、被重置、协议错误或无效响应。
  • 503:无可用后端、服务不可用或入口主动拒绝。
  • 504:连接/等待后端响应超过网关超时。

但业务应用也可能主动返回这些状态。必须结合:

  • 响应Header和Body特征。
  • Controller Access/Error Log。
  • upstream_addrupstream_status、分段耗时。
  • EndpointSlice。
  • 业务Pod日志和Trace。

二十四、入口重试和非幂等风险

Controller可能在连接失败、特定状态码或超时时重试另一后端。GET等幂等请求通常风险较低;POST订单、支付和外部通知可能已经在第一后端成功提交,只是响应丢失。

若入口自动重试:

text
Pod A完成下单
→ 返回连接被重置
→ Controller重试Pod B
→ 重复创建订单

必须:

  • 限制非幂等请求重试条件。
  • 使用业务幂等键。
  • 记录每次upstream尝试。
  • 超时后查询业务状态,而不是盲目重复。

二十五、Keep-Alive、连接池和扩容

Controller通常维护到Backend的Keep-Alive连接池。优点是减少TCP/TLS握手,风险包括:

  • 扩容后旧连接仍集中在旧Pod。
  • Pod终止时连接被重置。
  • 长连接占用不均。
  • Idle Timeout层层不一致。

入口、Service和客户端都可能按连接选择后端。观察负载时要区分请求数、连接数和并发,而不是只看Pod数量。

二十六、WebSocket和SSE

WebSocket从HTTP Upgrade成长连接;SSE保持长HTTP响应。需要检查:

  • Controller支持Upgrade/Header传递。
  • 读写/Idle Timeout。
  • 外部LB Idle Timeout。
  • Pod优雅终止和连接Drain。
  • 扩容不会迁移已有连接。
  • 客户端重连和Session恢复。

普通短请求健康不代表WebSocket稳定。

二十七、gRPC

gRPC通常基于HTTP/2,Backend协议和Controller配置必须一致。常见故障:

  • Controller按HTTP/1.1访问gRPC后端。
  • TLS/明文h2c模式不一致。
  • 长连接导致单Pod流量偏斜。
  • Header/Message大小限制。
  • Deadline与网关超时不一致。
  • 流式RPC被Idle Timeout中断。

配置方式依Controller,不能复制NGINX Annotation到云ALB后期望相同行为。

二十八、CORS应该放在哪一层

CORS是浏览器安全策略,可能由Controller、API Gateway或应用返回。多层同时设置容易产生重复/冲突Header。

生产建议:

  • 明确唯一主要策略所有者。
  • Origin使用白名单,不把带凭据请求配置为任意Origin。
  • 正确处理OPTIONS预检。
  • 缓存响应包含适当Vary。
  • 不把CORS当服务端认证授权。

Controller专有CORS Annotation升级时要做浏览器回归测试。

二十九、Annotation为什么有风险

Annotation把Controller特有能力带入Ingress,可能包括:

  • Rewrite。
  • 认证子请求。
  • Header修改。
  • 配置片段。
  • Canary。
  • 限流。

风险:

  • 不可移植。
  • Controller升级语义变化。
  • 配置片段可能注入危险代理配置。
  • 多租户可影响共享Controller。
  • 错误配置可能导致全局Reload失败。

平台应使用Admission Policy限制允许的Annotation,禁用高风险Snippet,分离公网/内网Controller并进行版本兼容测试。

三十、完整商业Ingress Demo

前提:平台已创建 public-nginx IngressClass、Controller和外部入口,业务Namespace已有Service和TLS Secret。

yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: commerce-api
  namespace: commerce
  labels:
    app: commerce-api
  annotations:
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "3"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "30"
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: public-nginx
  tls:
    - hosts:
        - api.example.com
      secretName: api-example-com-tls
  rules:
    - host: api.example.com
      http:
        paths:
          - path: /orders
            pathType: Prefix
            backend:
              service:
                name: order-api
                port:
                  name: http
          - path: /inventory
            pathType: Prefix
            backend:
              service:
                name: inventory-api
                port:
                  name: http

所有 nginx.ingress.kubernetes.io/* 都是示例Controller专有字段。使用前必须查目标版本文档,并验证Annotation被允许、单位正确、不会影响共享入口。

三十一、提交与观察

bash
kubectl apply --dry-run=server -f commerce-api-ingress.yaml
kubectl diff -f commerce-api-ingress.yaml
kubectl apply -f commerce-api-ingress.yaml

查看:

bash
kubectl get ingress commerce-api -n commerce -o wide
kubectl describe ingress commerce-api -n commerce
kubectl get ingressclass public-nginx -o yaml
kubectl get service,endpointslice -n commerce

Controller对象位置因平台而异,先定位:

bash
kubectl get deployment,daemonset,pod,service -A \
  -l app.kubernetes.io/component=controller

Label不是通用保证,必要时按Namespace/名称查找。

三十二、验证入口时不要先依赖公网DNS

先取得Ingress Status或Controller LB地址:

bash
kubectl get ingress commerce-api -n commerce \
  -o jsonpath='{.status.loadBalancer.ingress}{"\n"}'

使用正确Host/SNI测试:

bash
curl -vk --resolve api.example.com:443:<entry-ip> \
  https://api.example.com/orders/health

然后再验证公网DNS:

bash
nslookup api.example.com

这样能区分“入口规则错误”和“DNS尚未切换/缓存未过期”。

三十三、从外到内的生产排查顺序

mermaid
flowchart TD
    A["确认客户端错误、时间和Request ID"] --> B["DNS是否解析到正确环境入口"]
    B --> C["TCP/TLS是否成功,证书和SNI是否正确"]
    C --> D["外部LB和Controller是否收到请求"]
    D --> E["IngressClass、Host和Path是否匹配"]
    E --> F["Backend Service和端口是否存在"]
    F --> G["EndpointSlice是否有Ready地址"]
    G --> H["Controller到Pod连接/协议是否成功"]
    H --> I["业务应用和下游是否正常"]

每一步都要获取证据,不能从浏览器错误直接跳到重启Pod。

三十四、404排查

34.1 判断谁返回404

bash
curl -vk --resolve api.example.com:443:<entry-ip> \
  https://api.example.com/orders/1

检查响应Header/Body、Controller Access Log、应用日志。

34.2 Controller未匹配规则

检查:

bash
kubectl get ingress commerce-api -n commerce -o yaml
kubectl describe ingress commerce-api -n commerce
kubectl get ingressclass

原因:

  • Host不匹配。
  • 请求只访问IP,Host错误。
  • PathType/Path不匹配。
  • IngressClass错误或无人接管。
  • 规则尚未传播到全部Controller Pod。
  • 命中另一个默认/更具体规则。

34.3 应用返回404

Controller日志显示已选择上游且 upstream_status=404,应用日志有请求。检查:

  • Rewrite后路径。
  • Spring Context Path。
  • API版本前缀。
  • Method是否匹配。
  • Trailing Slash行为。

三十五、502排查

常见证据方向:

  • Connection refused:后端地址可达但端口未监听/targetPort错误。
  • Connection reset:后端进程关闭连接、Pod终止、协议不一致。
  • Invalid response:把HTTP发给HTTPS端口或反之。
  • TLS handshake to upstream failed:后端证书/SNI/CA问题。

命令:

bash
kubectl get service <backend> -n commerce -o yaml
kubectl get endpointslice -n commerce \
  -l kubernetes.io/service-name=<backend> -o yaml
kubectl get pod -n commerce -l app=<backend> -o wide
kubectl logs <backend-pod> -n commerce --tail=200

再从Controller Pod或同网络调试Pod直连实际上游协议和端口。

三十六、503排查

可能原因:

  • Service没有Ready Endpoint。
  • Controller配置未生成有效Backend。
  • 所有后端被标记不可用。
  • Controller过载/限流主动拒绝。
  • 应用自己返回503。

先判断入口日志是否有 upstream_addr。没有上游地址时优先检查Service/Endpoint和配置;有地址且上游状态503时查业务Pod。

发布期间全部Readiness失败,会让EndpointSlice没有Ready地址,Ingress返回503是保护行为。不要把Readiness改成固定成功,应修复新版本并保留旧可用副本。

三十七、504排查

504常表示入口等待后端超时,但必须分段:

  • 连接后端超时:网络、策略、端口、SYN无响应。
  • 已连接但响应头超时:应用线程池、锁、GC、数据库/Redis/下游慢。
  • 流式响应被Idle Timeout中断。

关联:

  • Controller connect/header/response时间。
  • Trace慢Span。
  • 应用线程池和连接池。
  • Pod CPU Throttle、GC和内存。
  • 数据库慢SQL、MQ和外部API。

只增加 proxy-read-timeout 会让用户等待更久,不能解决根因,还可能增加并发连接占用。

三十八、413排查

按层检查:

text
CDN/WAF限制
→ 外部LB限制
→ Ingress Controller body-size
→ API Gateway限制
→ Spring multipart/request限制
→ 应用业务校验

看请求是否进入Controller和应用日志,逐层找第一个拒绝者。

三十九、TLS证书错误排查

39.1 返回默认证书

常见原因:

  • 客户端未发送正确SNI。
  • Host没有对应TLS条目。
  • Secret不存在或Controller无权限读取。
  • 证书/私钥解析失败。
  • IngressClass未被该Controller接管。

39.2 域名不匹配

检查SAN,不要只看证书CN。api.example.com*.example.com 通常匹配一层,但 v1.api.example.com 不一定被该通配符覆盖。

39.3 证书链不完整

服务端只返回叶子证书而缺少中间CA,某些浏览器可能因缓存看似正常,其他客户端失败。Secret应包含正确full chain。

39.4 Secret更新但仍是旧证书

检查:

  • Secret ResourceVersion。
  • Controller是否Watch到更新。
  • Controller日志是否加载失败。
  • 多个Controller Pod是否全部更新。
  • 外部CDN/LB是否在更外层终止TLS。
  • 客户端/CDN缓存。

真实握手结果是最终证据。

四十、重定向循环排查

bash
curl -vkIL --max-redirs 10 https://api.example.com/orders

记录每个Location,检查:

  • TLS在哪一层终止。
  • X-Forwarded-Proto是否被可信传递。
  • Controller和应用是否同时强制HTTPS。
  • 域名规范化是否来回跳转。
  • Path尾斜杠Rewrite是否循环。

不要为了止损直接关闭所有HTTPS重定向而暴露明文敏感接口。

四十一、WebSocket/gRPC断连排查

检查:

  • 客户端到LB、LB到Controller、Controller到Backend每层Idle Timeout。
  • HTTP Upgrade或HTTP/2协议配置。
  • Controller Pod滚动更新和Drain。
  • 后端Pod优雅终止。
  • NetworkPolicy和连接重置。
  • 客户端心跳与重连。

短HTTP探针成功不覆盖长连接生命周期,应有专门的合成测试。

四十二、Ingress Controller自身容量

入口可能成为共享瓶颈,评估:

  • Controller副本和拓扑分散。
  • CPU/内存Request、Limit和Throttle。
  • Worker连接/文件描述符。
  • TLS握手CPU。
  • Keep-Alive和上游连接池。
  • 配置规模与Reload时长。
  • Access Log写入压力。
  • 大请求体临时磁盘。
  • 外部LB健康检查。

扩容Controller后,外部LB和连接复用是否均匀分配也需验证。

四十三、可观测性

Controller Access Log建议包含:

  • Request ID/Trace ID。
  • Host、Path模板、Method。
  • 客户端可信IP和代理链。
  • Ingress Namespace/Name。
  • Backend Service。
  • upstream address/status。
  • request/connect/header/response时间。
  • bytes、TLS版本和协议。
  • Controller Pod/版本。

指标:

  • 请求率、4xx/5xx、P95/P99。
  • 按Ingress/Service/版本的错误。
  • 活跃连接、连接建立失败。
  • TLS握手失败和证书到期。
  • 配置Reload成功/失败及耗时。
  • 无Endpoint Backend。
  • Controller CPU、内存、Throttle和FD。

日志不得记录Authorization、Cookie、Token、完整医疗/支付敏感Body。

四十四、多租户安全

共享Controller意味着一个团队的Ingress配置可能影响公共入口。治理:

  • Namespace RBAC限制谁能创建Ingress和Secret。
  • Admission校验Host归属、Class、Annotation白名单。
  • 禁止危险Snippet。
  • 公网和内网Controller隔离。
  • Secret最小读取和Namespace边界。
  • Controller Pod使用最小权限和只读文件系统。
  • WAF、限流和认证职责明确。
  • Host冲突检测和所有权登记。

不能让任意Namespace声明公司核心域名并被公网Controller接管。

四十五、灰度和金丝雀

标准Ingress API不统一定义按权重、Header、Cookie的Canary。不同Controller通过Annotation、CRD或Gateway API实现。

生产灰度需要:

  • 新旧Backend使用不可变Digest。
  • 按权重/用户/区域的明确分流规则。
  • 新旧版本独立指标。
  • 自动停止阈值。
  • Session和幂等兼容。
  • 配置传播与回滚验证。

不要只看到新版本总体1%流量就认为风险1%;特定支付渠道或高价值租户可能集中命中新版本。

四十六、Ingress、Gateway API和业务API Gateway

概念所属层主要能力
Ingress APIKubernetes入口API基础Host/Path/TLS到Service路由
Gateway APIKubernetes网络API体系GatewayClass、Gateway、HTTPRoute等角色分离和更丰富路由
Ingress Controller基础设施实现把Ingress/Gateway等对象变成真实数据面配置
Spring Cloud Gateway业务网关应用鉴权、业务路由、用户上下文、过滤器
云ALB/API Gateway云服务托管入口或API管理,能力依产品

典型链路可以是:

text
Client
→ Cloud LB / Ingress Controller
→ Spring Cloud Gateway
→ Service
→ Microservice Pod

也可以由 Gateway API直接把流量路由到业务Service。是否需要业务网关取决于认证、聚合和业务策略,不是每个系统都必须叠加所有层。

四十七、Gateway API为什么出现

Ingress API相对简单,大量高级能力依赖不可移植Annotation。Gateway API通过角色分离表达:

  • 基础设施提供者管理GatewayClass。
  • 集群运营者管理Gateway和Listener。
  • 应用团队管理HTTPRoute等路由。
  • 跨Namespace引用通过显式授权控制。

它不是把所有Controller实现变成完全一致;支持矩阵、Feature和版本仍需验证。迁移要并行测试Host、Path、TLS、Header、重试、超时和状态码。

四十八、发布和回滚Runbook

发布前:

  1. Server Dry Run和Admission校验。
  2. 检查Host所有权和DNS计划。
  3. 检查Backend Service/Port/Endpoint。
  4. 检查TLS Secret和证书有效期。
  5. 在测试Class/环境验证Controller Annotation。
  6. 使用 --resolve 绕过DNS做入口测试。
  7. 准备旧Ingress清单/版本和回滚条件。

发布中:

  • 观察Controller Reconcile/Reload。
  • 观察新旧Controller Pod配置一致性。
  • 观察4xx/5xx、P99、TLS失败和业务指标。
  • 记录Ingress ResourceVersion和Controller版本。

失败时:

  • 冻结继续扩散。
  • 判断DNS、TLS、路由、后端哪一层。
  • 回退错误Ingress/Annotation/Secret版本。
  • 不删除健康业务Pod掩盖入口错误。
  • 验证真实入口而不只看YAML。

四十九、常见误区

  1. 创建Ingress就有流量:必须有匹配Controller和外部入口。
  2. Ingress会自动创建DNS:需要DNS平台或ExternalDNS等组件。
  3. host同时决定证书:TLS还依赖SNI、Secret和SAN。
  4. 404一定是应用:可能是Controller默认后端。
  5. 502一定是Pod挂了:也可能端口/协议/TLS错误。
  6. 503一定没有Pod:也可能Controller或应用主动返回。
  7. 504调大超时就能修:根因可能线程池、锁和下游慢。
  8. Rewrite是Ingress标准:通常是Controller专有能力。
  9. Header里的客户端IP天然可信:必须定义可信代理链。
  10. rollout undo业务Pod能修入口错误:Ingress是独立对象。
  11. Secret Base64就是加密:私钥仍需严格保护。
  12. Gateway API等于Spring Cloud Gateway:一个是K8s网络API,一个是业务网关实现。

五十、面试标准回答

Ingress和Ingress Controller区别

Ingress是声明Host、Path、TLS和Backend的API对象,本身不监听或转发;Ingress Controller通过Informer观察IngressClass、Ingress、Service、EndpointSlice和Secret,生成/下发代理或云LB配置,Controller数据面才真正处理请求。

一次外部请求怎样到Pod

DNS把域名解析到外部LB或Controller入口;请求经Controller Service到Controller Pod,TLS阶段按SNI选证书,HTTP阶段按Host/Path选Ingress规则;Controller根据Backend Service解析Endpoint并连接Pod targetPort,响应沿代理链返回。具体是否经过ClusterIP取决于Controller实现。

Ingress 404怎么判断来源

用正确Host和SNI测试,结合响应特征、Controller Access Log和应用日志。Controller没有upstream时查Class、Host、Path和默认后端;日志显示upstream_status=404且应用收到请求时,查Rewrite、Context Path和应用Route。

502、503、504区别

通常502表示连接被拒绝/重置、协议或上游响应无效;503常表示无可用Endpoint或入口/应用主动不可用;504表示连接或等待响应超时。但不同Controller和应用都可能返回这些码,必须结合upstream地址、状态、分段耗时、Endpoint和Trace,不可只按码下结论。

TLS Secret更新为什么入口仍是旧证书

先验证Secret ResourceVersion和证书/私钥,再查Controller是否Watch并成功热加载、多个副本是否一致;确认更外层CDN/LB是否才是TLS终止点,最后用带SNI的openssl/curl从真实入口握手。对象更新不能证明数据面已生效。

Ingress和Gateway API区别

Ingress API提供相对基础的Host/Path/TLS路由,高级能力大量依赖Annotation;Gateway API通过GatewayClass、Gateway、Route等资源分离基础设施和应用角色,并表达更丰富路由。两者都需要Controller实现,也都不等于Spring Cloud Gateway业务网关。

五十一、学习实验与验收

实验一:没有Controller的Ingress

在隔离环境创建不被任何Class处理的Ingress,观察API对象存在但Status/代理配置不生效;再改为正确Class,观察Controller Event、日志和Status。

实验二:Host与SNI

使用入口IP分别执行直接IP访问和 curl --resolve,比较默认证书、404与正确路由,解释Host和SNI处于不同协议阶段。

实验三:Path和Rewrite

创建Exact、Prefix和Controller特有正则路由,让后端回显收到的URI。覆盖 /api/api//api/orders/api-old,验证真实匹配和重写结果。

实验四:证书轮换

在测试域名轮换TLS Secret,记录Secret版本、Controller日志、各Controller Pod配置和真实握手证书,证明控制面对象与数据面生效的区别。

实验五:制造502/503/504

  • targetPort指错制造连接失败。
  • 摘除所有Ready Endpoint观察503。
  • 后端延迟超过入口超时观察504。

分别保存Controller日志、EndpointSlice、应用日志和Trace。

实验六:长连接和优雅发布

建立WebSocket/gRPC流,滚动更新Controller和Backend,观察连接是否中断、Drain和客户端重连,调整有界Grace/Idle Timeout后复测。

验收清单

  1. 能列出Ingress、Class、Controller、Controller Service和LB职责。
  2. 能画出Controller Reconcile和数据流两张图。
  3. 能解释Host、SNI、DNS和证书SAN关系。
  4. 能准确区分三种PathType。
  5. 能判断404来自入口还是应用。
  6. 能根据upstream证据区分502/503/504。
  7. 能验证Secret轮换是否真正加载。
  8. 能解释Rewrite、超时和重试的实现边界。
  9. 能正确建立可信客户端IP代理链。
  10. 能排查WebSocket/gRPC长连接。
  11. 能治理危险Annotation和多租户Host冲突。
  12. 能区分Ingress、Gateway API和业务API Gateway。

关联知识点