-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
问题分析
根据你描述的现象,核心矛盾点非常清晰:
| 访问路径 | 结果 |
|---|---|
Pod 内 curl :8080 |
✅ 单条 Transfer-Encoding: chunked |
Nginx 机器 curl SVC LoadBalancer IP |
Transfer-Encoding: chunked |
| GLB → Nginx → GKE SVC | ❌ 502 |
重复 header 的根本原因:链路中某一层在已有 Transfer-Encoding: chunked 的情况下再次追加了该 header,而不是透传。
可能原因逐层排查
原因 1:GKE 集群内存在 Envoy/Istio Sidecar(最高嫌疑)
你的集群里同时存在 GKE Gateway,GKE Gateway 使用的是 Envoy 作为数据面。如果你的 Namespace 或 Pod 被注入了 Istio/Cloud Service Mesh sidecar,即使你绕开了 GKE Gateway 资源,流量依然会经过 sidecar proxy。
# 检查目标 Pod 是否有 sidecar 注入
kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].name}'
# 如果输出里包含 istio-proxy 或 envoy,则存在 sidecar
kubectl describe pod <pod-name> -n <namespace> | grep -i "istio\|envoy\|sidecar"
# 检查 namespace 是否开启了自动注入
kubectl get namespace <namespace> --show-labels | grep istio-injectionSidecar 导致重复 header 的机制:
graph LR
A[Nginx] --> B[SVC]
B --> C[Envoy Sidecar]
C --> D[App Container]
D -->|Transfer-Encoding: chunked| C
C -->|再次追加 chunked| B
B --> A
A -->|看到两条 chunked| E[502]
原因 2:GKE Gateway 的 BackendPolicy / HTTPRoute 仍在影响流量
即使你创建了新的普通 SVC(LoadBalancer),如果集群里的 GKE Gateway 有 HTTPRoute 通过 label selector 匹配到了你的 Pod,流量依然可能被 Gateway 数据面介入。
# 检查所有 HTTPRoute,看是否有匹配到你的 Service 或 Pod label
kubectl get httproute -A -o yaml | grep -A5 "backendRefs"
# 检查 GKEGateway 的 BackendPolicy
kubectl get gcpbackendpolicy -A
kubectl get healthcheckpolicy -A原因 3:Nginx 自身的 chunked 处理配置问题
当上游返回 Transfer-Encoding: chunked 时,Nginx 作为反代默认会解码 chunked 然后重新封装。但如果上游同时返回了某些触发 Nginx 直接透传的条件(如 proxy_pass 使用了 HTTP/1.0,或配置了 proxy_buffering off),可能导致行为异常。
# 检查你的 nginx 反代配置
# 关键指令
proxy_http_version 1.1; # 必须是 1.1,否则 chunked 行为异常
proxy_buffering off; # 这个配置会改变 chunked 处理方式
# 建议配置
location / {
proxy_pass http://<SVC-LB-IP>;
proxy_http_version 1.1;
proxy_set_header Connection ""; # 清除 hop-by-hop header
proxy_set_header Host $host;
# 明确处理 chunked
chunked_transfer_encoding on;
}原因 4:GLB(Internal HTTPS LB)的 HTTP/2 → HTTP/1.1 转换
Internal GLB 与后端(Nginx)之间默认使用 HTTP/2,而 HTTP/2 本身没有 Transfer-Encoding: chunked(使用 DATA frame 替代)。当 GLB 将响应从 HTTP/2 转换回 HTTP/1.1 时,如果后端响应已经包含了 chunked header,可能出现重复追加。
# 在 Nginx 机器上,测试直接 HTTP/1.1 vs HTTP/2 的响应差异
curl -v --http1.1 http://<SVC-LB-IP>/path 2>&1 | grep -i "transfer\|encoding"
curl -v --http2 https://<SVC-LB-IP>/path 2>&1 | grep -i "transfer\|encoding"推荐排查步骤
graph TD
A[开始排查] --> B{Pod 是否有 Sidecar}
B -->|有 istio-proxy| C[检查 namespace 注入标签]
C --> D[给该 namespace 打 sidecar.istio.io/inject=false\n或给 Pod 打 annotation 禁用]
B -->|无 Sidecar| E{HTTPRoute 是否匹配该 Pod}
E -->|有匹配| F[修改 HTTPRoute 或调整 Pod label 避免匹配]
E -->|无匹配| G[抓包确认重复 header 产生位置]
G --> H[tcpdump on Nginx 抓上游响应]
H --> I{重复 header 来自上游}
I -->|是| J[问题在 GKE 侧,检查 SVC/Endpoint]
I -->|否| K[问题在 Nginx 配置,调整 proxy_http_version]
D --> L[重新测试]
F --> L
K --> L
J --> L
关键抓包命令
# 在 Nginx 机器上抓包,过滤到 SVC LB IP 的流量
sudo tcpdump -i eth0 -A host <SVC-LB-IP> and port 80 -w /tmp/capture.pcap
# 用 tcpdump 直接看 header(不写文件)
sudo tcpdump -i eth0 -A host <SVC-LB-IP> and port 80 2>/dev/null | grep -i "transfer-encoding"快速验证方法
# Step 1: 确认 Pod 内响应干净
kubectl exec -it <pod> -- curl -sv http://localhost:8080/ 2>&1 | grep -i transfer
# Step 2: 确认 SVC ClusterIP 响应(在集群内节点上)
curl -sv http://<ClusterIP>:<port>/ 2>&1 | grep -i transfer
# Step 3: 确认 SVC LoadBalancer IP 响应(在 Nginx 机器上)
curl -sv http://<LB-IP>:<port>/ 2>&1 | grep -i transfer
# 如果 Step2 干净但 Step3 有重复 → 问题在 LB/Cloud 网络层
# 如果 Step2 已经重复 → 问题在集群内(sidecar 可能性极大)注意事项
- 优先排查 Sidecar 注入,这是混合使用 GKE Gateway 的集群里最常见的"幽灵干扰"来源
- 确认 Nginx
proxy_http_version 1.1且proxy_set_header Connection ""已配置 - Internal GLB 后端协议建议统一为 HTTP/1.1,避免协议转换引入额外 header 操作
- 如果确认是 sidecar 问题,不要直接删除 sidecar,而是通过 annotation 控制:
# 在 Pod spec 中禁用 sidecar 注入
annotations:
sidecar.istio.io/inject: "false"Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels