背景
k8s中的容器里面没有bash/sh可执行文件,使用kubectl exec指令无法进入容器;或者容器里面有bash/sh可执行文件,但是缺少其他用于排查问题的工具,如ping、tcpdump等。
解决方法
问题的原因是容器内的文件系统里没有对应的可执行文件,如果需要的可执行文件在主机上是存在的,可以在pod所在宿主机上执行nsenter进入容器对应进程的network namespace内执行相关命令即可。
nsenter
是一个用于进入命名空间(namespace)的实用工具。它允许你在已经运行的进程的命名空间中执行命令,以便查看或修改这些命名空间的状态。以下是 nsenter
的基本用法和一些常见参数:
基本用法:
nsenter [OPTIONS] [COMMAND] [ARG]...
常见参数:
-
-t
或--target
:指定目标进程的PID。这是进入其命名空间的目标进程。 -
-n
:用于进入网络命名空间,网络命名空间允许不同命名空间中的进程拥有独立的网络栈,包括独立的网络接口、IP地址、路由表等。这意味着不同网络命名空间中的进程可以隔离和互不干扰地运行网络应用程序。pod内的容器共享一个网络命名空间。 -
-u
:用于进入UTS命名空间,该空间用于隔离进程的hostname。 -
-i
:用于进入IPC命名空间,IPC命名空间允许不同命名空间中的进程拥有独立的进程间通信(IPC)资源,如消息队列、共享内存、信号等。这使得不同命名空间中的进程无法直接通信。 -
-m
:用于进入挂载命名空间,挂载命名空间允许不同命名空间中的进程拥有独立的文件系统挂载点和文件系统视图。这意味着每个挂载命名空间都可以有自己的根文件系统,独立于其他命名空间。 -
-p
:PID命名空间,PID命名空间允许不同命名空间中的进程有独立的进程ID(PID)空间,即不同命名空间中的进程可以拥有相同的PID而不会互相干扰。
实施例子
[root@localhost ~]# kubectl -n test exec -it nginx-test-xxx bash
[root@nginx-test-xxx nginx]# ip a
bash: ip: command not found
可以看到直接使用kubectl exec进入容器后发现没有ip指令,接下来我们可以通过nsenter来获取IP。
具体步骤:
-
查询pod所在节点
[root@localhost ~]# kubectl -n test get po nginx-test-xxx -owide
[root@localhost ~]# kubectl -n test get po nginx-test-xxx -owide|awk 'NR>1 {print $7}'
192.168.212.15
-
在pod所在节点上查询容器对应的进程id
#namespace和name支持正则表达式
[root@localhost ~]# crictl pods --namespace="test" --name="nginx-test-xxx.*"
POD ID CREATED STATE NAME NAMESPACE ATTEMPT
567f966d8d708 3 weeks ago Ready nginx-test-xxx test 0
#567f是前面指令获得的podId
[root@localhost ~]# crictl inspectp --output=go-template --template="{{.info.pid}}" 567f966d8d708
28186
-
进入进程的网络命名空间查询IP
[root@localhost ~]# nsenter -t 28186 -n -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2199: eth0@if2200: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1400 qdisc noqueue state UP group default
link/ether 00:00:00:5c:48:fe brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 100.126.0.46/16 brd 100.126.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::200:ff:fe5c:48fe/64 scope link
valid_lft forever preferred_lft forever
至此我们就获取到了容器的IP,可以使用kubectl get po -owide
来比较下二者的IP是否一致。除了ip指令,主机上的其他网络指令也能在容器内的网络命名空间执行,对于排查网络问题很有帮助。