容器排查工具:nsenter 与临时容器

获取进程或者容器ID

根据 容器 id 获取进程

1
crictl inspect -o go-template --template='{{index .info "pid"}}' ef80e5fd299001c62a1b039797c74cb9cac8bfc88488edd576ea64396c6b93ba

根据进程获取容器信息

1
2
3
ContainerID=`cat /proc/34056/cgroup   |  awk -F '/' '{print $NF}' | sed 's/cri-containerd-\(.*\).scope/\1/' |uniq`
podName=crictl inspect -o go-template --template='{{index .status.labels "io.kubernetes.pod.name"}}' $ContainerID
# crictl inspect $ContainerID # 查看容器信息

nsenter 使用

默认都有安装 yum install util-linux -y 自行安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
nsenter --help

用法:
nsenter [options] <program> [<argument>...]

Run a program with namespaces of other processes.

选项:
-t, --target <pid> 要获取名字空间的目标进程
-m, --mount[=<file>] enter mount namespace
-u, --uts[=<file>] enter UTS namespace (hostname etc)
-i, --ipc[=<file>] enter System V IPC namespace
-n, --net[=<file>] enter network namespace
-p, --pid[=<file>] enter pid namespace
-U, --user[=<file>] enter user namespace
-S, --setuid <uid> set uid in entered namespace
-G, --setgid <gid> set gid in entered namespace
--preserve-credentials do not touch uids or gids
-r, --root[=<dir>] set the root directory
-w, --wd[=<dir>] set the working directory
-F, --no-fork 执行 <程序> 前不 fork
-Z, --follow-context set SELinux context according to --target PID

-h, --help 显示此帮助并退出
-V, --version 输出版本信息并退出

eg: 进入容器的网路空间 pause 容器会共享网络等资源,进入 pause 一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@test-61 ~]# ps -ef |grep pause
65535 13324 13157 0 Aug24 ? 00:00:00 /pause

[root@test-61 ~]# nsenter -t 13324 -n
[root@test-61 ~]# ip addr
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
2: eth0@if66: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 32:89:55:bc:d8:f6 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 10.69.0.58/24 brd 10.69.0.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::3089:55ff:febc:d8f6/64 scope link
valid_lft forever preferred_lft forever

nsenter -t $PID -m -u -i -n -p /bin/sh 相当于 docker exec -it $container /bin/sh

临时容器

nsenter 的前提是能登上节点。如果只有 kubectl 权限,或者业务镜像是 distroless 这类连 shell 都没有的精简镜像,就该换成临时容器(ephemeral containers)。

临时容器:在原有的 pod 上,添加一个临时的 container,这个 container 可以包含很多需要使用到的排查工具,比如使用 busybox

参考官方文档

1
https://kubernetes.io/docs/concepts/workloads/pods/ephemeral-containers/

⚠️ 注:早期笔记里写的“还是实验功能 1.16 +,需要 --feature-gates=EphemeralContainers=true”已经过时。临时容器在 Kubernetes 1.23 转为 beta 并默认开启,1.25 已正式 GA,不用再开 feature gate,直接用 kubectl debug 就行。

1
2
3
4
5
# 往运行中的 pod 里注入一个 busybox 临时容器,并进入交互式 shell
kubectl debug -it <POD_NAME> --image=busybox --target=<CONTAINER_NAME> -- sh

# 临时容器不在 spec.containers 里,要单独查
kubectl get pod <POD_NAME> -o jsonpath='{.spec.ephemeralContainers[*].name}'

--target 指定要共享进程命名空间的目标容器,带上它才能在临时容器里看到目标容器的进程(需要容器运行时支持)。临时容器没有资源和调度保证,不能配置 portslivenessProbe 之类的字段,也不能重启或移除,排查完重建 pod 即可。

两者适用场景对比

维度 nsenter 临时容器
前提条件 能登上节点并有 root 权限 只需 kubectl 权限,集群 1.23+(1.25 起 GA)
工具来源 节点上装的工具(yum install util-linux 临时容器镜像自带,如 busyboxnetshoot
对 pod 的影响 完全无侵入,不改 pod 对象 会给 pod 追加一个临时 container,不可移除
典型用途 抓包,看 ip addriptablesconntrack 等命名空间内的状态 业务镜像里没有 shell / curl / ping 时,进去看进程、文件、发请求