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重写为何会改变应用路由。
学习目标
学完后应能:
- 区分 Ingress、IngressClass、Ingress Controller、Controller Service和外部LB。
- 解释创建 Ingress 对象后 Controller 如何 Reconcile 成真实代理配置。
- 从公网DNS追踪到业务Pod,并指出每一跳的证据。
- 区分 Host、SNI、Path、PathType、Backend Service和EndpointSlice。
- 解释 Exact、Prefix、ImplementationSpecific匹配边界。
- 解释 TLS握手、Secret、证书链、SAN、私钥和终止位置。
- 区分 TLS Termination、Re-encryption和Passthrough的实现边界。
- 说明 Rewrite、超时、请求体、重试、WebSocket和gRPC为什么依赖Controller。
- 正确处理 X-Forwarded-For、可信代理和客户端源IP。
- 根据404、502、503、504、413、TLS错误和重定向循环定位故障层。
- 设计生产入口的权限、隔离、可观测性、灰度和回滚。
- 区分 Kubernetes Gateway API 与 Spring Cloud Gateway等业务网关。
一、Ingress不等于Ingress Controller
| 对象 | 形态 | 主要职责 |
|---|---|---|
| Ingress | Kubernetes API对象 | 声明Host、Path、TLS和Backend |
| IngressClass | Kubernetes API对象 | 指定哪类Controller处理Ingress |
| Ingress Controller | 控制器进程 | Watch对象、校验并生成代理配置 |
| Controller Pod | 工作负载实例 | 真正监听80/443并代理请求 |
| Controller Service | Service对象 | 把流量送到Controller Pod |
| 外部LoadBalancer | 云/机房资源 | 把公网或专网流量送入集群入口 |
只创建 Ingress 而集群没有匹配的 Controller,结果通常是:
- API Server接受对象。
kubectl get ingress能看到规则。- 没有代理进程读取和执行。
- Status可能没有地址。
- 外部请求无法按规则转发。
这和“写了一份Nginx配置文件但没有启动Nginx”类似。
二、从公网域名到业务Pod的完整路径
一种常见云上路径:
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和相关引用对象。
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决定谁处理规则
示例:
apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
name: public-nginx
spec:
controller: k8s.io/ingress-nginx应用Ingress引用:
spec:
ingressClassName: public-nginxspec.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边界
旧清单常见:
kubernetes.io/ingress.class: nginx现代API优先使用 spec.ingressClassName。旧Annotation是否兼容取决于Controller版本,迁移时检查Release Notes,不要同时写冲突值。
五、Ingress对象结构
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写了:
host: api.example.com只表示请求的 Host 匹配规则。仍需:
- Controller入口有可达的IP/域名。
- DNS平台创建A/AAAA/CNAME记录。
- 记录指向正确环境入口。
- TTL与切换策略满足发布要求。
有些集群安装 ExternalDNS等Controller自动同步DNS,但那是额外组件和权限,不是Ingress API内置保证。DNS错误可能把生产域名指向测试入口,即使Ingress YAML完全正确。
七、Host匹配
客户端HTTP请求携带:
Host: api.example.comController按Host选择Virtual Host。测试时不能只访问IP:
curl -vk https://203.0.113.10/orders这可能发送错误Host并命中默认后端。应使用:
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规则约束,通常只匹配单层子域,例如:
*.example.com不要假设它匹配任意多层。证书SAN也必须覆盖对应域名。
八、PathType三种语义
8.1 Exact
path: /orders
pathType: Exact精确匹配 /orders,通常不匹配 /orders/123。
8.2 Prefix
path: /orders
pathType: Prefix按 / 分隔的路径元素匹配,通常匹配:
/orders
/orders/
/orders/123但不应把简单字符串前缀误认为一定匹配 /orders-old。
8.3 ImplementationSpecific
含义由IngressClass/Controller决定,可能支持正则或控制器特有规则。它降低可移植性,升级或更换Controller时必须重新验证。
九、多个Path如何选择
当多个规则都匹配时,Kubernetes Ingress规范倾向最长匹配路径;路径长度相同时,Exact通常优先于Prefix。Controller仍可能有实现细节和Annotation影响。
示例:
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可能来自三层:
- 外部CDN/LB/WAF。
- Ingress Controller默认后端或未匹配规则。
- 业务应用自身路由。
区分方法:
- 查看响应Header、Server标识和Request ID。
- 查看Controller Access Log是否有请求和上游信息。
- 查看业务Pod日志是否收到请求。
- 使用正确Host/SNI直接测试入口。
如果Controller日志有404且没有上游,优先查Host/Path/Class;如果上游返回404且业务日志有请求,查应用Context Path和Rewrite。
Ingress资源也可声明自己的默认后端:
spec:
defaultBackend:
service:
name: safe-default-backend
port:
name: http它用于该Ingress没有规则匹配时的默认服务。Controller还可能配置全局默认后端,两者优先和合并行为需要按实现验证。默认后端应返回最小安全响应,不泄露内部Host、代理版本、集群路径或调试信息。
十一、Rewrite不是Ingress通用字段
标准Ingress描述匹配和Backend,不定义所有控制器的路径重写语义。NGINX Ingress等实现通过Annotation提供Rewrite。
示意(仅适用于对应Controller和版本):
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请求:
/api/orders/1重写后可能发送:
/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终止:
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结构和安全
创建:
kubectl create secret tls api-example-com-tls -n commerce \
--cert=fullchain.pem \
--key=private-key.pem \
--dry-run=client -o yaml典型Secret:
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等受控方案。
十五、证书必须验证哪些内容
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
Client --HTTPS--> Ingress Controller --HTTP--> Backend入口解密,便于七层路由、WAF和指标。Controller到Pod之间未加密,需要可信内网、NetworkPolicy或其他加密措施。
16.2 Re-encryption
Client --HTTPS--> Controller --HTTPS--> BackendController终止客户端TLS,再以独立TLS连接后端,需要验证后端证书、SNI和CA。具体Annotation/CRD由Controller决定。
16.3 TLS Passthrough
Client --TLS--> Controller/LB --TLS--> Backend入口不解密,通常只能依据SNI做有限四层/五层选择,无法读取HTTP Path和Header。标准Ingress支持程度有限,属于Controller特有能力。
三者不能只凭“端口是443”判断,应查看Controller配置和抓取握手证据。
十七、证书自动化和cert-manager边界
cert-manager等Controller可根据Certificate/Issuer资源申请并续期证书,再更新Secret。完整链路包括:
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 时,可能产生循环:
Client HTTPS
→ LB终止TLS并用HTTP访问Controller/应用
→ 应用认为当前是HTTP并重定向HTTPS
→ Client再次HTTPS
→ 循环应明确TLS终止点,并只信任来自已知代理的Forwarded Header。
十九、客户端源IP和Forwarded Header
经过多层代理后,后端TCP源IP通常是Controller Pod/Node,而不是用户。常用Header:
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。正确治理:
- 外层可信LB覆盖或规范追加Header。
- Controller只信任配置的代理CIDR。
- 应用框架只在请求来自可信代理时解析Forwarded Header。
- 日志同时记录连接源、解析后的客户端IP和代理链。
- 限流与审计使用经过信任边界处理的地址。
否则攻击者可以伪造IP绕过限流或污染审计。
二十、Controller直接暴露还是经过LoadBalancer
常见Controller Service:
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: httpsexternalTrafficPolicy: Local常用于保留源IP,但要求外部LB只把流量送到有本地Controller Pod的Node。Controller Deployment的拓扑分布、PDB、Readiness和节点容量都会影响入口可用性。
应用团队通常不维护Controller Service,这属于平台层资源;页面示例用于理解链路。
二十一、请求体大小限制
文件上传收到413通常是入口限制,不一定到达业务Pod。NGINX Ingress示意:
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名称和单位依实现而异。必须遵循超时预算:
客户端总超时
> 入口处理与重试预算
> 应用自身总预算
> 单次下游调用超时如果外层30秒、应用60秒,入口会先返回504,但应用可能继续执行并产生副作用,客户端重试又可能重复下单。
二十三、502、503和504不能只靠状态码猜
不同Controller定义可能不同,通用方向:
- 502:连接后端失败、被重置、协议错误或无效响应。
- 503:无可用后端、服务不可用或入口主动拒绝。
- 504:连接/等待后端响应超过网关超时。
但业务应用也可能主动返回这些状态。必须结合:
- 响应Header和Body特征。
- Controller Access/Error Log。
upstream_addr、upstream_status、分段耗时。- EndpointSlice。
- 业务Pod日志和Trace。
二十四、入口重试和非幂等风险
Controller可能在连接失败、特定状态码或超时时重试另一后端。GET等幂等请求通常风险较低;POST订单、支付和外部通知可能已经在第一后端成功提交,只是响应丢失。
若入口自动重试:
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。
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被允许、单位正确、不会影响共享入口。
三十一、提交与观察
kubectl apply --dry-run=server -f commerce-api-ingress.yaml
kubectl diff -f commerce-api-ingress.yaml
kubectl apply -f commerce-api-ingress.yaml查看:
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 commerceController对象位置因平台而异,先定位:
kubectl get deployment,daemonset,pod,service -A \
-l app.kubernetes.io/component=controllerLabel不是通用保证,必要时按Namespace/名称查找。
三十二、验证入口时不要先依赖公网DNS
先取得Ingress Status或Controller LB地址:
kubectl get ingress commerce-api -n commerce \
-o jsonpath='{.status.loadBalancer.ingress}{"\n"}'使用正确Host/SNI测试:
curl -vk --resolve api.example.com:443:<entry-ip> \
https://api.example.com/orders/health然后再验证公网DNS:
nslookup api.example.com这样能区分“入口规则错误”和“DNS尚未切换/缓存未过期”。
三十三、从外到内的生产排查顺序
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
curl -vk --resolve api.example.com:443:<entry-ip> \
https://api.example.com/orders/1检查响应Header/Body、Controller Access Log、应用日志。
34.2 Controller未匹配规则
检查:
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问题。
命令:
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排查
按层检查:
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缓存。
真实握手结果是最终证据。
四十、重定向循环排查
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 API | Kubernetes入口API | 基础Host/Path/TLS到Service路由 |
| Gateway API | Kubernetes网络API体系 | GatewayClass、Gateway、HTTPRoute等角色分离和更丰富路由 |
| Ingress Controller | 基础设施实现 | 把Ingress/Gateway等对象变成真实数据面配置 |
| Spring Cloud Gateway | 业务网关应用 | 鉴权、业务路由、用户上下文、过滤器 |
| 云ALB/API Gateway | 云服务 | 托管入口或API管理,能力依产品 |
典型链路可以是:
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
发布前:
- Server Dry Run和Admission校验。
- 检查Host所有权和DNS计划。
- 检查Backend Service/Port/Endpoint。
- 检查TLS Secret和证书有效期。
- 在测试Class/环境验证Controller Annotation。
- 使用
--resolve绕过DNS做入口测试。 - 准备旧Ingress清单/版本和回滚条件。
发布中:
- 观察Controller Reconcile/Reload。
- 观察新旧Controller Pod配置一致性。
- 观察4xx/5xx、P99、TLS失败和业务指标。
- 记录Ingress ResourceVersion和Controller版本。
失败时:
- 冻结继续扩散。
- 判断DNS、TLS、路由、后端哪一层。
- 回退错误Ingress/Annotation/Secret版本。
- 不删除健康业务Pod掩盖入口错误。
- 验证真实入口而不只看YAML。
四十九、常见误区
- 创建Ingress就有流量:必须有匹配Controller和外部入口。
- Ingress会自动创建DNS:需要DNS平台或ExternalDNS等组件。
host同时决定证书:TLS还依赖SNI、Secret和SAN。- 404一定是应用:可能是Controller默认后端。
- 502一定是Pod挂了:也可能端口/协议/TLS错误。
- 503一定没有Pod:也可能Controller或应用主动返回。
- 504调大超时就能修:根因可能线程池、锁和下游慢。
- Rewrite是Ingress标准:通常是Controller专有能力。
- Header里的客户端IP天然可信:必须定义可信代理链。
rollout undo业务Pod能修入口错误:Ingress是独立对象。- Secret Base64就是加密:私钥仍需严格保护。
- 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后复测。
验收清单
- 能列出Ingress、Class、Controller、Controller Service和LB职责。
- 能画出Controller Reconcile和数据流两张图。
- 能解释Host、SNI、DNS和证书SAN关系。
- 能准确区分三种PathType。
- 能判断404来自入口还是应用。
- 能根据upstream证据区分502/503/504。
- 能验证Secret轮换是否真正加载。
- 能解释Rewrite、超时和重试的实现边界。
- 能正确建立可信客户端IP代理链。
- 能排查WebSocket/gRPC长连接。
- 能治理危险Annotation和多租户Host冲突。
- 能区分Ingress、Gateway API和业务API Gateway。
