跳到主要内容

nsenter:不装工具也能排查容器内部

阅读需 2 分钟

生产容器基本都是精简镜像,里面没有 ss、tcpdump,甚至没 sh。想抓个包、看个端口,总不能往运行中的容器里装东西。nsenter 是这类场景的救星:从宿主机直接进入容器的命名空间执行命令,容器里缺工具也没关系——用的是宿主机的。

原理一句话​

容器隔离的本质是 Linux namespace。nsenter 是对 setns 系统调用的封装:指定一个目标进程的 PID,把当前命令「塞进」它的某个命名空间里执行。容器里 1 号进程的所有命名空间就是这个容器的隔离边界,进去就等于站在容器内部。

基本用法​

nsenter -t <PID> [命名空间选项] <要执行的命令>

常用命名空间选项:

选项进入的空间典型用途
-nnetwork抓包、看端口、看路由(用得最多)
-mmount看容器视角的文件系统挂载
-ppid看容器内的进程列表
-iipc共享内存、消息队列
-uuts主机名
-a全部完全进入容器环境

也可以不通过 PID、直接指定命名空间文件,比如 Kubernetes 注册的:nsenter --net=/var/run/netns/cni-xxx ...

先拿到容器的 PID​

# Docker
PID=$(docker inspect -f '{{.State.Pid}}' <容器名>)

# Kubernetes 节点上(找 Pod 沙箱的 PID)
crictl pods --name <pod名> # 拿到 pod 沙箱 ID
crictl inspect <沙箱ID> | grep pid # 里面的 info.pid

K8s 里一个 Pod 的所有容器共享网络命名空间,所以进 pause 沙箱的网络空间就等于进了整个 Pod 的网络。

实战场景​

抓容器网卡的包(最经典,配合 tcpdump 笔记一起看):

nsenter -t $PID -n tcpdump -i eth0 -nn port 80

看容器里实际监听的端口(镜像里没 ss 时):

nsenter -t $PID -n ss -lnt

看容器视角的挂载和磁盘:

nsenter -t $PID -m -- df -h
nsenter -t $PID -m -- mount | grep nfs

验证容器内 DNS 解析:

nsenter -t $PID -n -- nslookup kubernetes.default

完全进入容器环境执行一系列命令(近似 docker exec,但不要求容器里有 shell):

nsenter -t $PID -a /bin/bash

几个坑​

  • 需要 root 或 CAP_SYS_ADMIN,普通用户直接跑会 permission denied
  • 目标进程退出,命名空间就没了:拿着 PID 正准备进,容器恰好重启,PID 失效,报 setns: cannot set namespace——重新取一次 PID 即可
  • -m 里别乱动:在挂载命名空间里 umount 或挂东西影响的是容器本体,只读看看就好
  • 进网络命名空间后看到的 eth0 是容器的网卡,和宿主机的 eth0 不是一回事,别抓错方向

小结​

nsenter 把「容器里没工具」这个借口彻底消灭了:宿主机的 tcpdump、ss、ip、nslookup 全都是容器的排查工具。记住核心三板斧——docker inspect 拿 PID、nsenter -t $PID -n 进网络空间、完事退出不留痕。它比进容器装调试镜像优雅得多,也不会污染运行环境。