最近在做流媒体相关的一些服务,它通过 k3s 部署在盒子上,我们的服务偶尔会出现拉流资源被拉爆的情况,需要定位一下是否存在资源泄漏的情况。由于基本流媒体服务是端口复用的,我们则选择 lsof -i : 来做这样的事情,但是在宿主机上看不到相关的信息,一定得进容器去看,但是部署的容器一般不带 lsof 等网络工具,每次定位问题需要 apt update && apt install,还是挺麻烦的。于是深入了解了一下,应该如何做?

lsof -i :

这是最直观的工具,可以看到针对这个 port 有打开哪些资源,但是在我们现在这个环境下失效了,什么都没有输出。但是系统又是 work 的,信息到底隐藏到哪里了呢?

/proc/net/tcp

linux proc 伪文件系统提供了很多有意思的功能,例如这个文件就记录着系统里目前运行着的 tcp 链接,那么我们尝试读取这个文件,由于这个文件记录的数据是 16 进制的,进行 grep 时,我们需要转换一下,我这里的端口是 9500,转换后是 251C。 关于 tcp 文件的细节,可以参考 https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt。

$ cat /proc/net/tcp | grep 251c

data 返回是空白的,什么数据都没有,只能再尝试别的方法了。

/proc/

系统里什么都看不到,只能继续去对应的进程的空间里看看了,fd 是最常用的 ,我们能看到很多数据,一些 socket,一些 file,但是并无法知道 socket 到底是什么,是一个 unix socket 还是别的什么,也看不到端口。 data2

那么 /proc//net/tcp 呢? ![data3](/assets/leakage_link/screenshot-20221230-152505.png)

哈,果然在这里,能看到打开的 251C 的链接了,通过这里我们能够看到真实 work 的数据了。

WHY

为什么会这样?

本身问题也比较简单,要搞明白这个问题,需要了解这些网络相关的东西,做容器的同学应该都听说过 iptables 和 linux namespaces。后者为每个容器划分独立的网络空间,而 iptables 提供转发的功能。这里我们不深入讨论这两个系统,了解即可。

/proc/net/tcp 的问题是,如果是在 namespace 里打开的链接,在这里就不会体现了。进程在 net namespace 中监听端口,iptables 将收到的网络数据进行转发。

既然知道是 namespace,一切都简单了,我们有 nsenter 工具,以及对应的 namespace

$ nsenter --net /proc/<pid>/ns/net -- lsof -i :9500

data4

至此,完美解决问题,不需要再登进容器 apt update && apt install lsof 了。

建议大家去熟悉 proc 各个功能,在监控不足的环境下定位问题,有奇效。