巧用 Nsenter 调取宿主机工具调试容器内程序
时间:2022-07-28
本文章向大家介绍巧用 Nsenter 调取宿主机工具调试容器内程序,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
公众号关注 「奇妙的 Linux 世界」
设为「星标」,每天带你玩转 Linux !
nsenter 是一个可以用来进入到目标程序所在 Namespace 中运行命令的工具,一般常用于在宿主机上调试容器中运行的程序。
nsenter 安装
nsenter 位于 util-linux 包中,一般常用的 Linux 发行版都已经默认安装。如果你的系统没有安装,可以使用以下命令进行安装:
$ yum install util-linux
nsenter 用途
一个比较典型的用途就是进入容器的网络命名空间。通常容器为了轻量级,大多都是不包含较为基础网络管理调试工具,比如:ip、ping、telnet、ss、tcpdump 等命令,给调试容器内网络带来相当大的困扰。
nsenter 命令可以很方便的进入指定容器的网络命名空间,使用宿主机的命令调试容器网络。
除此以外,nsenter 还可以进入 mnt、uts、ipc、pid、user 等命名空间,以及指定根目录和工作目录。
nsenter 用法
首先看下 nsenter 命令的语法:
$ nsenter [options] [program [arguments]]
options:
-a, --all enter all namespaces of the target process by the default /proc/[pid]/ns/* namespace paths.
-m, --mount[=<file>]:进入 mount 命令空间。如果指定了 file,则进入 file 的命名空间
-u, --uts[=<file>]:进入 UTS 命名空间。如果指定了 file,则进入 file 的命名空间
-i, --ipc[=<file>]:进入 System V IPC 命名空间。如果指定了 file,则进入 file 的命名空间
-n, --net[=<file>]:进入 net 命名空间。如果指定了 file,则进入 file 的命名空间
-p, --pid[=<file>:进入 pid 命名空间。如果指定了 file,则进入 file 的命名空间
-U, --user[=<file>:进入 user 命名空间。如果指定了 file,则进入 file 的命名空间
-t, --target <pid> # 指定被进入命名空间的目标进程的 pid
-G, --setgid gid:设置运行程序的 GID
-S, --setuid uid:设置运行程序的 UID
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录
如果没有给出 program,则默认执行 $SHELL
。最常用的参数组合是:
# 有的版本不一定有 -a 这个参数
$ nsenter -a -t <pid> <command>
$ nsenter -m -u -i -n -p -t <pid> <command>
nsenter 使用实例
- 进入 docker 容器的 namespace 中运行指定程序
使用 nsenter 进入 docker 容器的 namespace 是非常简单的,通常你只需要以下两步:
# 获取相应的 Dokcer 容器的 PID
$ PID=$(docker inspect --format {{.State.Pid}} <container_name_or_ID>)
# 使用相应参数进入程序所在的不同 NameSpace
$ nsenter -m -u -i -n -p -t $PID <command>
下面我们来看几个实例:
- 进入指定程序所在的所有命名空间
$ docker run --rm --name test -d busybox sleep 10000
8115009baccc53a2a5f6dfff642e0d8ab1dfb95dde473d14fb9a06ce4e89364c
$ docker ps |grep busybox
8115009baccc busybox "sleep 10000" 9 seconds ago Up 8 seconds test
$ PID=$(docker inspect --format {{.State.Pid}} 8115009baccc)
$ nsenter -m -u -i -n -p -t $PID ps aux
PID USER TIME COMMAND
1 root 0:00 sleep 10000
7 root 0:00 ps aux
$ nsenter -m -u -i -n -p -t $PID hostname
8115009baccc
- 进入指定程序所在的网络命名空间
运行一个 Nginx 容器,查看该容器的 Pid:
$ docker inspect -f {{.State.Pid}} nginx
5645
然后,使用 nsenter 命令进入该容器的网络命令空间:
$ nsenter -n -t5645
$ 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
18: eth0@if19: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
- 进入 Kubernetes 容器的 namespace 中运行指定程序
如果是在 Kubernetes 中,在得到容器 Pid 之前,你还需先获取容器的 ID,可以使用如下命令获取:
$ kubectl get pod nginx -n web -o yaml|grep containerID
- containerID: docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
或者更为精确地获取 containerID:
$ kubectl get pod nginx -n web -o template --template='{{range .status.containerStatuses}}{{.containerID}}{{end}}'
docker://cf0873782d587dbca6aa32f49605229da3748600a9926e85b36916141597ec85
其它的步骤就和前面进入 Docker 容器的命名空间类似了。
参考文档
- https://www.googgle.com
- https://staight.github.io/2019/09/23/nsenter%E5%91%BD%E4%BB%A4%E7%AE%80%E4%BB%8B/
- https://mozillazg.com/2020/04/nsenter-usage.html
- 关于服务器的运行寿命 你应该知道这些事
- WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[下篇]
- WCF技术剖析之二十一: WCF基本的异常处理模式[上篇]
- 树大招风:细数2017年加密货币市场的幺蛾子事件
- 如何解决HP QC(Quality Center)在Windows 7下不能工作的问题
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[上篇]
- 5个典型实例启发:什么是数据可视化
- 智能家居“智商”不够,能靠情商来补吗
- 大话MVP
- AngularJS in Action读书笔记1——扫平一揽子专业术语
- MS Enterprise Library 5.0发布!!
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
- 《Enterprise Library深入解析与灵活应用》博文系列汇总
- 使命必达: 深入剖析WCF的可靠会话[概念篇]
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- CentOS7.8下编译muduo库找不到Boost库报错的解决方法
- 使用 OWIN 搭建 OAuth2 服务器
- Hive on spark下insert overwrite partition慢的优化
- 系统学习Lambda表达式
- 一文搞懂 Flink Kafka Consumer 类两阶段提交
- 在 Nowin 下运行 ASP.NET 5 Beta 2
- Bytom侧链Vapor源码浅析-节点出块过程
- Kubernetes Pod OOM 排查日记
- Netty之旅:你想要的NIO知识点,这里都有!
- (数据科学学习手札92)利用query()与eval()优化pandas代码
- Spring Boot 集成 Elasticsearch 实战
- Python之错误和异常、模块(基础系列第四篇)
- Spark存储Parquet数据到Hive,对map、array、struct字段类型的处理
- 为什么这条异常没有上报? HTTP 429
- 三问Spring事务:解决什么问题?如何解决?存在什么问题?