参数

复制

容器内没有tcdump、route、ifconfig等网络命令,给我们网络调试、排查问题带来了很大的困难。我们知道,容器有自已的网络命名空间,所以我们只需要进入到容器的网络命名空间,再利用主机上的命令进行调试就可以了

1.运行一个nginx容器
1
# 通过宿主机的8000端口映射到容器的80端口$ docker run -d -p 8000:80 nginx:1.26.2 nginx
2.找到容器中PID为1的进程在宿主机上对应的PID
1
$ docker inspect -f {{.State.Pid}} nginx

我们可以在宿主机上通过ps命令,确认4439进程就是对应我们容器中运行的nginx进程:

图片

3.使用nsenter命令进入容器网络命名空间,并抓包

1
# 进入到进程号为4439的网络命名空间$ nsenter -t 4439 -n

然后,我们可以使用ifconfig命令查看该网络命名空间下的网络设备信息(这跟我们进入容器执行ifconfig命令看到的是一致的):

图片

我们也可以通过以下命令确认容器的ip就是172.17.0.3

1
$ docker inspect -f {{.NetworkSettings.IPAddress}} nginx

图片

最后我们就可以运行tcpdump命令进行抓包了,在容器的网络命名空间中捕获80端口的流量,然后访问宿主机的8000端口,即可抓取到相应的网络报文了:

图片

以上就和我们进入容器运行tcpdump命令抓取报文效果一样。


如果是在kubernetes中,我们该如何找到Pod中对应容器的网络命令空间呢?

1.启动一个 nginx Pod
1
$ kubectl run nginx --image=nginx:1.26.2

确认容器running:

![图片](

2.获取Pod中的容器ID

1
$ kubectl get pods nginx -o jsonpath='{.status.containerStatuses[0].containerID}'containerd://f79e81d5d641387306e2a583f7501ddd7c6b72d578969b65c1a0e021c00a7ed3

案例中nginx Pod只有一个名称为nginx的container,如果Pod中有多个container,使用containerStatuses[0]选取Pod中第一个container的containerID也没有关系,因为在k8s里,Pod中所有container是共享同一个网络命名空间的;

3.获取容器中PID为1的进程在宿主机上对应的进程PID
1
$ crictl inspect --template '{{.info.pid}}' -o go-template f79e81d5d641387306e2a583f7501ddd7c6b72d578969b65c1a0e021c00a7ed312191
4.使用nsenter命令进入容器网络命名空间
1
# 进入到进程号为12191的网络命名空间$ nsenter -t 12191 -n

接下去就可以使用tcdump、route、ifconfig等网络调试命令进行问题排查诊断了。