一次 GKE Sidecar 场景下的连通性排查实录

文章目录

    • 问题现象
    • 先说结论
    • 排查目标
    • 第一步:先做最小对照,排除"节点问题"
    • [第二步:检查 namespace 差异,锁定 sidecar 是关键变量](#第二步:检查 namespace 差异,锁定 sidecar 是关键变量)
    • [第三步:检查原生 NetworkPolicy,避免误判](#第三步:检查原生 NetworkPolicy,避免误判)
    • [第四步:为什么带 sidecar 时 `nc -vz` 会显示 `open`](#第四步:为什么带 sidecar 时 nc -vz 会显示 open)
    • [第五步:不要再靠 `nc` 判断,改用真实请求验证](#第五步:不要再靠 nc 判断,改用真实请求验证)
    • 第六步:用抓包确认,包到底有没有离开节点
    • [第七步:节点本机再测一次,彻底确认问题不在 Pod](#第七步:节点本机再测一次,彻底确认问题不在 Pod)
    • 第八步:为什么另一个目标地址又是通的
    • 最终判断
    • [这次排查最值得记住的 5 个经验](#这次排查最值得记住的 5 个经验)
      • [1. 先控制变量,不要上来就认定是节点问题](#1. 先控制变量,不要上来就认定是节点问题)
      • [2. `nc -vz` 很方便,但在透明代理场景下不可靠](#2. nc -vz 很方便,但在透明代理场景下不可靠)
      • [3. sidecar 存在时,优先用 `curl` / `wget` / `openssl s_client`](#3. sidecar 存在时,优先用 curl / wget / openssl s_client)
      • [4. 抓包是分界线](#4. 抓包是分界线)
      • [5. 节点本机测试非常有价值](#5. 节点本机测试非常有价值)
    • 一套可复用的排查顺序
    • 收尾

问题现象

由于涉及到敏感信息,所以这里不会有任何的截图或者日志信息,只记录排查过程和思路

某个运行在 Kubernetes 集群中的 Pod,需要访问一个内网目标的 443 端口。

表面现象很诡异:

  • 同一个集群里,有的 Pod 访问正常
  • 有的 Pod 访问超时
  • 带 sidecar 的 Pod 用 nc -vz 看起来是 open
  • 但用 curlwget 又不一定成功

这种现象很容易让人误判成:

  • 某个 namespace 有问题
  • 某个节点有问题
  • Istio 把流量"改好了"

这次排查的价值,恰恰在于把这些看似合理但并不准确的判断,一步步排除掉。

先说结论

最终确认的问题不在集群内部,而在集群外部网络路径。

更准确地说:

  • 从 Pod 发往目标 443 的 TCP SYN 已经离开节点
  • 节点本机直连该目标也超时
  • 节点抓包看不到任何来自目标的返回包

因此可以判断:

  • 不是 Kubernetes NetworkPolicy 问题
  • 不是 sidecar 本身"修复"了网络
  • 不是节点没有把包发出去
  • 而是节点之后的链路、网关、对端 ACL 或回程路由存在问题

另外,一个非常容易踩坑的点是:

在透明代理场景下,nc -vz 显示 open,不一定等于目标端口真的端到端可达。

排查目标

我们需要回答 3 个问题:

  1. 问题到底和节点有关,还是和 Pod 运行环境有关?
  2. sidecar 到底改变了什么?
  3. nc 显示 open,为什么真实访问仍然可能失败?

第一步:先做最小对照,排除"节点问题"

最开始的怀疑对象通常是节点。

因为看起来像这样:

  • Pod A 在节点 1 上访问超时
  • Pod B 在节点 2 上访问正常

但这种对比往往是不成立的,因为同时变了多个变量:

  • 节点变了
  • namespace 变了
  • Pod 网段可能也变了
  • sidecar 注入状态也可能变了

所以正确做法是控制变量。

我们做了两组对照:

  • 在原本"正常"的 namespace 中,把 Pod 调度到怀疑有问题的节点
  • 在原本"异常"的 namespace 中,把 Pod 调度到原本正常的节点

结果发现:

  • 只要放到某个 namespace 中,访问就容易成功
  • 放到另一个 namespace 中,即使换节点也还是超时

这个结果说明:

问题不优先落在节点,而是更像和 Pod 的运行上下文有关。

第二步:检查 namespace 差异,锁定 sidecar 是关键变量

继续对比两个 namespace,发现一个关键差异:

  • 正常的 Pod 有 sidecar
  • 异常的 Pod 没有 sidecar

进一步确认后可以看到:

  • 一个 namespace 开启了 mesh 注入
  • 另一个没有开启

这时很容易产生一个判断:

有 sidecar 的流量能通,没 sidecar 的不通,所以一定是 Istio 帮忙"打通"了网络。

这个判断只对了一半(这里属于马后炮,哈哈)。

它说明 sidecar 是关键变量,但还不能说明 sidecar 真正把远端连通了。

第三步:检查原生 NetworkPolicy,避免误判

下一步检查目标 namespace 的原生 NetworkPolicy

重点看两件事:

  • 是否存在 policyTypes: [Egress]
  • 是否存在默认拒绝出站的规则

结果看到的都是 Ingress 策略,没有影响出站。

这一步很重要,因为它排除了一个常见误区:

不是所有"某 namespace 访问不通"的问题,都来自 NetworkPolicy。

第四步:为什么带 sidecar 时 nc -vz 会显示 open

这是这次排查里最容易误导人的地方。

先看无 sidecar 时发生了什么:

  1. nc 直接对目标 IP:443 发起 TCP connect
  2. 只有远端真正返回 SYN-ACK
  3. nc 才会认为连接建立成功,并打印 open

所以在无 sidecar 场景下:

nc -vzopen 基本可以理解为远端 TCP 端口真的可达。

但有 sidecar 时,流程变了:

  1. 应用进程仍然以为自己在连目标 IP:443
  2. Pod 里的 iptables 规则会把这个连接透明重定向到本地 Envoy
  3. ncconnect() 可能先成功连到本地代理
  4. 于是 nc 立即打印 open
  5. 但这并不等于 Envoy 到远端的 upstream 连接已经成功

这就是为什么:

  • nc -vz 显示 open
  • 但更真实的请求手段,比如 curlwgetopenssl s_client,仍然可能失败

一句话概括:

透明代理场景里,nc -z 测到的可能只是"应用到本地代理"这一跳。

第五步:不要再靠 nc 判断,改用真实请求验证

为了验证 sidecar 场景下到底有没有真正访问到远端,需要换工具。

推荐这类命令:

bash 复制代码
curl -vk --connect-timeout 5 --max-time 8 https://<目标IP>/

或者:

bash 复制代码
wget -S -O- --timeout=5 https://<目标IP>

它们会逼出更真实的行为:

  • TCP connect
  • TLS 握手
  • 应用层请求

也就是说,这时失败就更接近真实业务失败,而不是"本地代理接住了连接"。

第六步:用抓包确认,包到底有没有离开节点

这是这次排查的分水岭。

在节点上抓目标 443 的流量:

bash 复制代码
tcpdump -i any -nn -vvv host <目标IP> and port 443

然后从无 sidecar Pod 发起请求。

抓包看到的是:

  • Pod 源地址发出 TCP SYN
  • 包经过节点出口网卡发出
  • 没有任何来自目标的返回包

也就是说:

包已经离开节点,但没有回包。

这一点非常关键。它直接排除了以下方向:

  • Pod 没有把包发出去
  • 节点没转发
  • 集群内部策略把包挡住了

如果抓包只看到反复 SYN 重传,而看不到任何 SYN-ACK,通常说明:

  • 对端没回
  • 中间链路静默丢弃
  • 或回程路由有问题

第七步:节点本机再测一次,彻底确认问题不在 Pod

为了避免怀疑"只有 Pod 流量异常",还需要从节点本机直接访问目标:

bash 复制代码
curl -vk --connect-timeout 5 --max-time 8 https://<目标IP>/

结果同样超时。

这一步把问题进一步定性为:

不是 Pod 专属问题,而是节点到目标的外部网络路径本身就不通。

到这里,范围已经收得非常小:

  • 不是 Kubernetes 内部问题
  • 不是 sidecar 配置问题
  • 而是节点之后的网络问题

第八步:为什么另一个目标地址又是通的

为了防止把问题夸大成"整个远端网段都不通",还做了一个关键对照。

在同一条自定义路由下,对另一个目标地址测试,结果是通的。

这说明:

  • 不是整条路由坏了
  • 不是整个远端地址段都不通
  • 而是某个具体目标,或者它后面的某段链路有问题

这类现象最常见的原因有两个:

  1. 目标侧 ACL / 防火墙只放行部分来源
  2. 目标侧或中间网关缺少某个源网段的回程路由

最终判断

综合所有实验,可以得出一个比较扎实的判断:

已确认的事实

  • 有无 sidecar,不能单靠 nc -vz 来判断端到端可达性
  • 目标 443 的 SYN 已经离开 GKE 节点
  • 节点本机直连目标也超时
  • 抓包中没有任何目标回包
  • 对同一路由下的另一个目标地址访问正常

可以排除的方向

  • namespace 原生 NetworkPolicy
  • 节点本地未发包
  • Pod 网络本身损坏
  • "Istio 一定把问题修好了"这种简单结论

最有可能的根因

  • 集群外部链路问题
  • 中间网关后的转发异常
  • 目标侧 ACL / 防火墙限制
  • 或目标侧对源网段的回程路由缺失

这次排查最值得记住的 5 个经验

1. 先控制变量,不要上来就认定是节点问题

只看"这个 Pod 在某个节点失败、另一个节点成功"没有意义。

要把节点、namespace、sidecar 状态拆开做对照。

2. nc -vz 很方便,但在透明代理场景下不可靠

它适合做粗探测,不适合在 sidecar 透明拦截场景里做最终定案。

3. sidecar 存在时,优先用 curl / wget / openssl s_client

这些命令会逼出真实的远端连接和握手行为,比 nc -z 更可信。

4. 抓包是分界线

一旦确认 SYN 已离开节点但无回包,问题基本就已经不在集群内部了。

5. 节点本机测试非常有价值

它能快速区分:

  • 是 Pod 专属问题
  • 还是节点到外部目标本来就不通

一套可复用的排查顺序

以后再遇到类似问题,可以直接按下面顺序走:

  1. 先做最小对照,分离节点、namespace、sidecar 三个变量
  2. 检查原生 NetworkPolicy 是否真的影响 Egress
  3. 对带 sidecar 的 Pod,不要只看 nc -vz
  4. curl / wget / openssl s_client 做真实访问验证
  5. 在节点上抓目标端口流量,确认包有没有离开节点
  6. 在节点本机直接访问目标,确认问题是否已经存在于节点之外
  7. 再去看外部网关、ACL、回程路由

收尾

这次问题表面上看像是 "有 sidecar 能通,没 sidecar 不通"。

但真正的技术重点不是 sidecar 本身,而是:

透明代理会改变你观察连接是否成功的方式。

如果工具选错了,就会被一个看起来正常的 open 带偏。

真正可靠的证据来自两类手段:

  • 真实请求
  • 节点抓包

只要把这两件事做扎实,问题通常都会很快从"像是集群内部故障",收敛到"其实是集群外部网络路径异常"。

相关推荐
亚空间仓鼠3 小时前
Docker容器化高可用架构部署方案(六)
docker·容器·架构
前端老曹3 小时前
Docker 从入门到放弃:完整指南
运维·docker·容器
Cat_Rocky4 小时前
k8s-持久化存储,粗浅学习
java·学习·kubernetes
咖啡里的茶i5 小时前
在Docker环境中安装Hadoop cluster 实验报告一
hadoop·docker·容器
汪汪大队u5 小时前
续:从 Docker Compose 到 Kubernetes(2)—— 服务优化与排错
网络·后端·物联网·struts·容器
rabbit_pro5 小时前
Docker compose部署Ollama使用模型
linux·运维·docker
ILL11IIL6 小时前
k8s的pod管理及优化
云原生·容器·kubernetes
咖啡里的茶i7 小时前
在Docker环境中安装Hadoop cluster 实验报告三
docker
笑洋仟7 小时前
docker的overlay2目录占用磁盘空间很大,清理办法
运维·docker·容器
木雷坞7 小时前
2026 年 5 月国内可用 Docker 镜像源列表与配置方法
运维·docker·容器