Skip to content

Kubernetes Pod 网络抓包实战指南

生产环境排查 Pod 网络问题时,经常遇到业务容器镜像精简、没有 tcpdump 的尴尬情况。Kubernetes 的 Ephemeral Containers(临时调试容器)特性可以在不重启 Pod 的前提下,向运行中的 Pod 注入一个共享网络命名空间的调试容器,直接抓取业务容器进出的流量。本文以排查一个 order-service 服务的 HTTPS 连接异常(Connection reset)为例,完整介绍从注入临时容器、tcpdump 抓包、导出 pcap 文件到 Wireshark 分析的全流程。

适用对象:Kubernetes 1.23 及以上版本的集群(Ephemeral Containers 自 1.23 起为 Beta 默认开启,1.25 起 GA)。

一、环境准备与目标确认

1.1 设置环境变量

为避免重复输入,建议先设置环境变量:

bash
# 设置目标 Pod 和命名空间
pod="order-service-7d9f4b5c6-x8k2m"
namespace="default"

# 设置 debug 镜像(推荐 netshoot,内置 tcpdump)
debug_image="harbor.example.com/base/nicolaka/netshoot:v0.15"

1.2 查找目标容器名称(关键步骤)

--target 参数必须指定为 Pod 内原有的业务容器名,否则临时容器无法与业务容器共享网络命名空间。

bash
# 方法1:查看 Pod 详情(最直观)
kubectl describe pod $pod -n $namespace

# 方法2:直接提取容器名(适合脚本自动化)
target_container=$(kubectl get pod $pod -n $namespace -o jsonpath='{.spec.containers[0].name}')
echo "目标容器: $target_container"

kubectl describe 输出的 Containers: 段落中确认业务容器名称(本例为 order-service)。

二、注入临时 Debug 容器

2.1 执行注入命令

bash
kubectl debug -it $pod \
  -n $namespace \
  --image=$debug_image \
  --target=$target_container \
  --profile=general

参数说明:

  • --target:指定共享网络命名空间的原容器。
  • --profile=general:使用标准权限配置(推荐)。如需抓包权限受限,可改用 --profile=sysadmin
  • 系统会自动生成临时容器名(如 debugger-xxxxx)。

预期输出:

text
Targeting container "order-service". If you don't see processes from this container it may be because the container runtime doesn't support this feature.
Defaulting debug container name to debugger-gd8hd.

请记录生成的临时容器名(如 debugger-gd8hd),后续下载抓包文件时需要用到。

2.2 进入 debug 容器的交互式 shell

bash
kubectl exec -it $pod \
  -c debugger-gd8hd \
  -n $namespace \
  -- sh

2.3 验证网络共享

进入容器后,执行 ip addrnetstat -tulpn,确认看到的网络接口和监听端口与目标业务容器一致。若看到的接口只有 loopback,说明 --target 未生效,需检查容器运行时是否支持 Ephemeral Containers 的网络共享。

三、抓包操作流程

3.1 抓包命令(针对 HTTPS/SSL)

在 debug 容器内执行:

bash
# 抓取特定目标 IP 的 443 端口流量
tcpdump -i eth0 \
  "(host 203.0.113.20 or host 203.0.113.10) and port 443" \
  -s 0 -w /tmp/ssl_capture.pcap

参数说明:

  • -i eth0:监听主网络接口(Pod 内通常为 eth0)。
  • -s 0:抓取完整数据包。默认只抓前 68 字节,分析 TLS 握手等应用层协议必须设为 0。
  • -w:保存为 pcap 文件。注意临时容器退出后文件会丢失,抓完需及时导出。

3.2 触发复现与停止

  1. 保持抓包终端运行,让 tcpdump 持续抓包。
  2. 新开一个终端,触发业务请求(调用接口,复现 SSL 报错场景)。
  3. 返回抓包终端按 Ctrl + C 停止抓包,tcpdump 会打印统计信息:
text
152 packets captured
152 packets received by filter
0 packets dropped by kernel
  1. 执行 ls -lh /tmp/ssl_capture.pcap 确认文件已生成且大小合理。

四、导出抓包文件到本地

4.1 确认临时容器名称

如果忘记了注入的容器名,可通过以下命令查询:

bash
# 查看 Pod 的临时容器定义
kubectl get pod $pod -n $namespace -o yaml | grep -A 10 ephemeralContainers

在输出中查找 name: debugger-xxxxx

4.2 复制文件到本地

bash
# 语法:kubectl cp <namespace>/<pod>:<容器内路径> <本地路径> -c <容器名>
kubectl cp $namespace/$pod:/tmp/ssl_capture.pcap \
  ./ssl_capture.pcap \
  -c debugger-gd8hd

常见报错处理:

  • 如果报错 tar: removing leading '/',可忽略,这是 tar 的提示信息,文件通常已成功复制,本地 ls -lh ssl_capture.pcap 确认即可。
  • 如果报错 tar not found(目标容器内没有 tar 命令),改用 kubectl exec 流式传输导出:
bash
kubectl exec $pod -n $namespace -c debugger-gd8hd \
  -- cat /tmp/ssl_capture.pcap > ssl_capture.pcap

使用流式导出时建议校验文件完整性(对比两端文件大小,或用 Wireshark 打开确认无截断)。

五、本地分析与故障排查

5.1 使用 Wireshark 分析

bash
wireshark ssl_capture.pcap

关键显示过滤器:

过滤器用途
tcp.flags.reset == 1查看连接重置(RST)包
tls.handshake查看 TLS 握手过程(旧版 Wireshark 用 ssl.handshake
ip.addr == 203.0.113.10过滤特定对端 IP
tls.alert_message查看 TLS 协议级告警(旧版为 ssl.alert_message

5.2 连接重置(Connection reset)问题定位

针对客户端报 Connection reset 类异常,在 pcap 中重点关注三点:

  1. RST 包来源:过滤 tcp.flags.reset == 1,确认 RST 是客户端还是服务端(本例为 203.0.113.10)发出的。若 RST 来自一个既非客户端也非服务端的中间 IP,需排查中间链路(防火墙、LB、安全设备)。
  2. TLS 握手阶段:查看 Client HelloServer Hello 是否成功交换。如果只有 Client Hello 没有响应,可能是对端或中间设备拒绝;如果 Server Hello 后立即 RST,需检查证书协商。
  3. Alert 报文:过滤 tls.alert_message 查看是否有协议级错误,如 bad_certificatehandshake_failureprotocol_version 等,可定位到证书或 TLS 版本不兼容问题。

5.3 TLS 握手失败快速判断

抓包现象可能原因
发出 Client Hello 后直接收到 RST对端端口未监听 TLS、中间设备拦截
收到 Alert: handshake_failure加密套件(Cipher Suite)不匹配
收到 Alert: bad_certificate / unknown_ca客户端不信任服务端证书链
收到 Alert: protocol_version两端 TLS 版本无交集(如服务端仅 TLS 1.3,客户端仅 TLS 1.2)
TCP 三次握手即失败(SYN 无响应或 SYN-ACK 后 RST)与 TLS 无关,属于网络连通性问题

六、清理资源

Ephemeral Container 无法单独删除,它会随 Pod 生命周期结束自动消失。退出 debug 终端后无需额外操作:

bash
# 退出 debug 容器 shell 即可,临时容器保留在 Pod 中但不再占用资源
exit

# 如需彻底移除临时容器,只能删除重建 Pod(生产环境慎用,确认业务可滚动重建后再执行)
kubectl delete pod $pod -n $namespace

同时记得清理本地和容器内的 pcap 文件:抓包文件可能包含业务数据明文(HTTP 场景),分析完成后应及时删除。

附录 A:常用 tcpdump 过滤表达式速查

场景表达式
指定主机host 203.0.113.10
指定端口port 443
源地址/目的地址src host 203.0.113.10 / dst host 203.0.113.10
源端口/目的端口src port 8080 / dst port 443
指定网段net 192.168.10.0/24
组合条件(host 203.0.113.10 or host 203.0.113.20) and port 443
排除某端口not port 22
只看 TCP 握手包`tcp[tcpflags] & (tcp-syn
只看 RST 包tcp[tcpflags] & tcp-rst != 0
DNS 查询udp port 53
ICMP(ping)icmp
HTTP 明文流量tcp port 80

其他常用参数:

参数说明
-i any监听所有接口(排查多网卡场景)
-n不做域名解析,直接显示 IP(建议总是加上)
-nn同时禁用端口名解析(直接显示端口号)
-c 1000抓满 1000 个包自动停止
-C 100 -W 5按 100MB 滚动切分文件,最多保留 5 个(防磁盘写满)
-v / -vv / -vvv递增的详细输出

附录 B:生产环境抓包安全注意事项

事项说明
权限控制kubectl debug 创建 Ephemeral Container 需要 pods/ephemeralcontainers 的 update 权限,生产环境应通过 RBAC 收敛到少数运维账号
数据敏感pcap 文件可能包含业务请求明文(HTTP、数据库协议等),禁止外发,分析完成后立即删除本地与容器内文件
磁盘占用长时间抓包或全量抓包(无过滤条件)可能写满容器 tmpfs,务必加 -C/-W 限制文件大小,或加精确的过滤表达式
性能影响tcpdump 本身开销很小,但 -i any 全接口无过滤抓包在高流量节点上仍可能造成 CPU 抖动,优先精确过滤目标 IP/端口
变更留痕生产集群执行抓包前建议走变更流程并通知业务方,抓包窗口尽量避开业务高峰
镜像合规debug 镜像建议推送到内部 Harbor(如 harbor.example.com)统一管控,避免临时拉取公网镜像失败或引入安全风险

故障速查

现象排查方向
kubectl debug 报错 ephemeral containers 不支持集群版本低于 1.23,或 apiserver 未开启 EphemeralContainers 特性门控(1.23 前需手动开启)
进入 debug 容器后看不到业务容器的网络接口--target 指定的容器名错误,或容器运行时不支持网络命名空间共享
kubectl cp 报错 tar not found目标容器无 tar,改用 kubectl exec -- cat file > local 流式导出
tcpdump 报错 permission denied临时容器缺少 NET_RAW/NET_ADMIN 能力,注入时使用 --profile=sysadmin
pcap 文件为 0 字节过滤表达式过于严格无匹配流量,先去掉过滤条件验证接口是否有流量
Wireshark 打开 pcap 报截断错误流式导出时连接中断,重新导出并校验文件大小