当前位置: 首页 > 科技观察

如何在KubernetesPod中优雅抓包

时间:2023-03-16 01:00:16 科技观察

在使用Kubernetes的过程中,经常会遇到一些棘手的网络问题,需要对Pod中的流量进行抓包分析。但是一般使用的镜像是没有tcpdump命令的。以往常用的方法简单直接暴力:登录节点所在节点,使用root账号进入容器,然后安装tcpdump。抓包有时需要拉回本地使用Wireshark分析。而且整个过程非常繁琐,跨越好几个环境。就在前几天,我也做了一次抓包问题的排查。本次介绍几种快速抓取网络数据包的方法。TL;DR几种方法各有优缺点,不建议在生产环境中使用。如果一定要用,我个人更喜欢kubectldebugtemporarycontainer的方案,但是这个方案也有缺点。使用额外的容器:该方案为Pod增加一个额外的容器,使用静态编译的tcpdump进行抓包,利用多容器共享网络空间的特点,适用于distroless容器。缺点是需要修改原来的Pod,调试容器重启会导致Pod重启。kubectl插件ksniff:一个kubectl插件。支持特权和非特权容器,可以将捕获重定向到wireshark或tshark。非特权容器的实现稍微复杂一些。kubectldebugtemporarycontainer:该方案对distroless容器有很好的支持,临时容器退出不会导致Pod重启。缺点是1.23版本的临时容器才进入内测阶段;并且作者在将抓取的数据重定向到本地Wireshark时会报不支持数据格式的错误。环境使用k3d创建k3s集群,这里的版本是1.23:$k3dclustercreatetest--imagerancher/k3s:v1.23.4-k3s1捕获的对象使用了Pipy[1]运行的echo服务(返回请求的主体内容):$kubectlrunecho--imageaddozhang/echo-server--image-pull-policyIfNotPresent创建一个NodePort服务以便于访问:$kubectlexposepodecho--nameecho--port8080--typeNodePortmountcontainer在上一篇文章中介绍几种调试distroless容器的方法时,我们采用了修改Pod添加额外容器的方法。新容器使用imageaddozhang/static-dumpimage。一个静态编译的tcpdump被添加到这个图像中。修改的Pod:apiVersion:v1kind:Podmetadata:labels:run:echoname:echospec:containers:-image:addozhang/echo-serverimagePullPolicy:IfNotPresentname:echoresources:{}-image:addozhang/static-dumpimagePullPolicy:IfNotPresentname:sniffcommand:['sleep','1d']dnsPolicy:ClusterFirstrestartPolicy:Alwaysstatus:{}重新部署后,可以使用如下命令抓取网络包重定向到本地Wireshark:$kubectlexec-iecho-c嗅探——/static-tcpdump-ieth0-U-w-|wireshark-k-i-debug-containerkubectlpluginksniffksniff[2]是一个kubectl插件,它使用tcpdump和Wireshark远程监控Pod爬取中的网络数据包。使用这种方式既可以发挥Wireshark的强大功能,又可以减少对pod的影响。ksniff的实现是将一个静态编译的tcpdump上传到Pod,然后将tcpdump的输出重定向到本地的Wireshark进行调试。核心可以理解为tcpdump-w-|wireshark-k-i-,类似于之前使用调试容器的解决方案。通过krew[3]安装:$kubectlkrewinstallsniff或者下载release包,手动安装:$unzipksniff.zip$makeinstall特权模式容器使用说明参考ksniff官方说明[4],这里我们只需要执行下面的命令,默认情况下会重定向到Wireshark,无需显式指定:$kubectlsniffecho-ndefault-f"port8080"除了使用Wireshark,ksniff还可以使用其命令行模式tshark:$kubectlsniffecho-ndefault-f"端口8080"-o-|tshark-r-unprivilegedmodecontainer对于非特权容器,不能使用上述方法,会收到如下错误信息:INFO[0000]command:'[/tmp/static-tcpdump-iany-U-w-port8080]'exitingCode:'1',stdErr:'static-tcpdump:any:Youdon'thavepermissiontocaptureonthatdevice(socket:Operationnotpermitted)但是,Ksniff也提供了对此类容器的支持。通过添加-p参数,ksniff会在节点上创建一个可以访问DockerDaemon的新pod,然后将容器附加到目标容器的网络命名空间,进行抓包。注意笔者使用的是k3s环境。执行命令时需要通过参数指定DockerDaemon的socket地址--socket/run/k3s/containerd/containerd.sock$kubectlsniffecho-ndefault-f"port8080"--socket/run/k3s/containerd/containerd.sock-p|wireshark-k-i-ksniff-priviledgedkubectldebug临时容器也就是之前介绍的kubectldebug,就是给Pod增加一个临时容器[5]。同样的,我们可以使用这种方式在Pod网络上抓包,临时容器我们使用addozhang/static-dump镜像。$kubectldebug-iecho--imageaddozhang/static-dump--targetecho--/static-tcpdump-ieth0原来的临时容器应该是最接近完美的解决方案:不需要向目标容器上传任何文件,无需修改Pod,无需重启,无需权限,支持distroless容器。但是,当尝试重定向到Wireshark或tshark时,我得到Datawrittentothepipeisneitherinasupportedpcapformatnorinpcapngformat..最后折腾了一番,还是没能解决问题。