如何优雅的在 Kubernetes Pod 内进行网络抓包

公众号关注 「奇妙的 Linux 世界」

设为「星标」,每天带你玩转 Linux !

700d12811ffb40f66d31e4b99ee86582.png

使用 Kubernetes 时,经常会遇到一些棘手的网络问题需要对 Pod 内的流量进行抓包分析。然而所使用的镜像一般不会带有 tcpdump 命令,过去常用的做法简单直接暴力:登录到节点所在节点,使用 root 账号进入容器,然后安装 tcpdump。抓到的包有时还需要拉回本地,使用 Wireshark 进行分析。而且整个过程非常繁琐,跨越几个环境。

正好前几天也做了一次抓包问题排查,这次就介绍一下快速进行网络抓包的几种方法。

TL;DR

几种方法各有优缺点,且都不建议在生产环境使用。假如必须使用,个人倾向于 kubectl debug 临时容器的方案,但这个方案也有不足。

  • 使用额外容器:这种方案为了 Pod 添加一个额外的容器,使用了静态编译的 tcpdump 进行抓取,借助了多容器共享网络空间的特性,适合 distroless 容器。缺点是需要修改原来的 Pod,调式容器重启会引起 Pod 重启。

  • kubectl plugin ksniff:一个 kubectl 插件。支持特权和非特权容器,可以将捕获内容重定向到 wireshark 或者 tshark。非特权容器的实现会稍微复杂。

  • kubectl debug 临时容器:该方案对于 distroless 容器有很好的支持,临时容器退出后也不会导致 Pod 重启。缺点是 1.23 的版本临时容器才进入 beta 阶段;而且笔者在将捕获的数据重定向到本地的 Wireshark 时会报数据格式不支持的错误。

环境

使用 k3d 创建 k3s 集群,这里版本选择 1.23:

$ k3d cluster create test --image rancher/k3s:v1.23.4-k3s1

抓包的对象使用 Pipy[1] 运行的一个 echo 服务(返回请求的 body 内容):

$ kubectl run echo --image addozhang/echo-server --image-pull-policy IfNotPresent

为了方便访问,创建一个 NodePort Service:

$ kubectl expose pod echo --name echo --port 8080 --type NodePort

挂载容器

在之前的文章我们介绍调试 distroless 容器的几种方法时曾用过修改 Pod 添加额外容器的方式,新的容器使用镜像 addozhang/static-dump 镜像。这个镜像中加入了静态编译的 tcpdump

修改后的 Pod:

apiVersion: v1
kind: Pod
metadata:
  labels:
    run: echo
  name: echo
spec:
  containers:
  - image: addozhang/echo-server
    imagePullPolicy: IfNotPresent
    name: echo
    resources: {} 
  - image: addozhang/static-dump
    imagePullPolicy: IfNotPresent
    name: sniff
    command: ['sleep', '1d']
  dnsPolicy: ClusterFirst
  restartPolicy: Always
status: {}

重新部署后,就可以使用下面命令将抓取网络包并重定向到本地的 Wireshark:

$ kubectl exec -i echo -c sniff -- /static-tcpdump -i eth0 -U -w - | wireshark -k -i -
3d27eb133a187614dddd537725812653.gif
debug-container

kubectl plugin ksniff

ksniff[2] 是一个 kubectl 插件,利用 tcpdump  和 Wireshark 对 Pod 中的网络包实现远程抓取。使用这种方法既可以借助 Wireshark 的强大功能,又能降低对 Pod 的影响。

ksniff 的实现是上传一个静态编译的tcpdump 到 Pod 中,然后将 tcpdump 的输出重定向到本地的 Wireshark 进行调试。

核心可以理解成 tcpdump -w - | wireshark -k -i -,与前面使用 debug 容器的方案类似。

安装

通过 krew[3] 安装:

$ kubectl krew install sniff

或者下载发布包,手动安装:

$ unzip ksniff.zip
$ make install

特权模式容器

使用说明参考 ksniff 官方说明[4],这里我们只需要执行如下命令,默认就会重定向到 Wireshark,不需要显示地指定:

$ kubectl sniff echo -n default -f "port 8080"
bd533e88096184fc43607f035457b02c.gif
ksniff

除了使用 Wireshark,可以使用其命令行模式的 tshark

$ kubectl sniff echo -n default -f "port 8080" -o - | tshark -r -

非特权模式容器

对于无特权的容器,就无法使用上面的方法了,会收到如下的错误提示:

INFO[0000] command: '[/tmp/static-tcpdump -i any -U -w - port 8080]' executing successfully exitCode: '1', stdErr :'static-tcpdump: any: You don't have permission to capture on that device
(socket: Operation not permitted)

不过,Ksniff 对此类容器也提供了支持。通过添加 -p 参数,ksniff 会创建一个新的可以访问节点上 Docker Daemon 的 pod,然后将容器附加到目标容器的网络命名空间,并执行报文捕获。

注意,笔者使用的是 k3s 的环境,执行命令时需要通过参数指定 Docker Daemon 的 socket 地址 --socket /run/k3s/containerd/containerd.sock

$ kubectl sniff echo -n default -f "port 8080" --socket /run/k3s/containerd/containerd.sock -p | wireshark -k -i -
6e931e8c0aa3cb95a0a7b585e3cbb59d.gif
ksniff-priviledged

kubectl debug 临时容器

接下来也是之前介绍过的 kubectl debug ,也就是为 Pod 添加临时容器[5]

同样我们可以通过这种方法对 Pod 的网络进行抓包,临时容器我们使用 addozhang/static-dump 镜像。

$ kubectl debug -i echo --image addozhang/static-dump --target echo -- /static-tcpdump -i eth0
4e1cccb5101fe48c3fb3f89bd10643a1.gif
ephermeral-sniff-stdout

大家能发现这里将捕获的内容直接输出在标准输出中了,而不是重定向到本地的 Wireshark。

原本临时容器应该是其中最接近完美的方案:不需上传任何文件目标容器、无需修改 Pod、无需重启、无需特权、支持 distroless 容器。然而,当尝试重定向到 Wireshark 或者 tshark 的时候,会遇到 Data written to the pipe is neither in a supported pcap format nor in pcapng format. 问题。

最后经过一番折腾,也未能解决该问题。有解决了问题的朋友,也麻烦评论告知一下。感谢!

参考资料

[1]

Pipy: https://github.com/flomesh-io/pipy

[2]

ksniff: https://github.com/eldadru/ksniff

[3]

krew: https://github.com/GoogleContainerTools/krew

[4]

ksniff 官方说明: https://github.com/eldadru/ksniff#usage

[5]

临时容器: https://kubernetes.io/zh/docs/concepts/workloads/pods/ephemeral-containers/

本文转载自:「云原生指北」,原文:https://tinyurl.com/2p944dw2,版权归原作者所有。欢迎投稿,投稿邮箱: editor@hi-linux.com。

94813384144a51ed32c5549281dfacac.gif

最近,我们建立了一个技术交流微信群。目前群里已加入了不少行业内的大神,有兴趣的同学可以加入和我们一起交流技术,在 「奇妙的 Linux 世界」 公众号直接回复 「加群」 邀请你入群。

9bf6cb746bdcb8b9c2a90b77e8a2e635.png

你可能还喜欢

点击下方图片即可阅读

c1a2169f2f725ef34e2fb95a773344d7.png

24 个常见的 Docker 疑难杂症处理技巧

6d3ea2295699e11856ffbc84da596bf2.png
点击上方图片,『美团|饿了么』外卖红包天天免费领

a0a70aaa4369c308ec4c3969b69a5a33.png

更多有趣的互联网新鲜事,关注「奇妙的互联网」视频号全了解!

Kubernetes Pod 网络不通可能有多种原因。 首先,可能是 Pod 所属的 Node 网络故障。这可能是由于 Node 上的网络问题,例如网卡故障、网络配置错误或网络连接断导致的。解决这个问题的方法可以是检查 Node 上的网络连接、查看网络配置或重启 Node。 其次,可能是 Pod 内部容器的网络配置问题。每个 Pod 可以包含多个容器,这些容器之间通过网络进行通信,但容器的网络配置可能存在问题。例如,容器的 IP 地址冲突、容器的网络策略限制、容器的防火墙规则等等。解决这个问题的方法可以是检查容器的网络配置、查看容器日志或重新启动容器。 另外,还有可能是集群网络插件的问题。Kubernetes 支持多种网络插件(如Flannel、Calico等),这些插件负责连接 Pod 和 Node 之间的网络。如果网络插件配置有问题,可能会导致 Pod 网络不通。解决这个问题的方法可以是检查网络插件的配置、查看插件的日志或重新配置插件。 最后,还有可能是网络策略的限制导致 Pod 网络不通。Kubernetes 提供了网络策略功能,可以控制 Pod 之间的网络访问权限。如果网络策略配置有误或设置了不正确的规则,可能会导致 Pod 之间无法通信。解决这个问题的方法可以是检查网络策略的配置、查看策略的规则或调整策略的设置。 总之,Kubernetes Pod 网络不通可能有多种原因,需要根据具体情况进行排查,并寻找对应的解决方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值