容器通过 Linux Namespace 技术,对网络、PID、用户等等信息的隔离。
从进程的角度来说,你可以在 Host 上看到所有容器内的进程。
或者更准确的说,当你在 Host 所在的 root PID namespace 时,可以看到其所有下层 PID namespace 里的进程。
当你在 Host 上得到了一个进程的 PID,比如是 6052,那么怎么知道它在其所属的 PID namespace 里的 PID 呢?
Linux Kernel >= 4.1
host_pid
指代你在 root PID namespace 里看到的进程 ID
从 Linux Kernel 4.1 开始,在 /proc/[host_pid]/status
里有一个 NSpid 字段,它就是其在自己的 PID namespace 里的 PID:
|
|
Linux Kernel < 4.1
在 Linux Kernel 4.1 之前的版本则没有 NSpid
字段可以利用,那么就需要迂回一点,下面有两种方法。
方法一
利用 procfs 的 /proc/[pid]/sched
伪文件来匹配查找。
如果你打开任何进程的 /proc/[pid]/sched
文件,可以看到类似下面的内容:
|
|
8416
是进程在下层 namespace 里的 PID,而 918
是进程在 root namespace 里的 PID。
所以你可以这样:
- 进入
host_pid
的 namespace - 用 ps 列出这个 namespace 下所有的 PID,下面称为
cont_pid
,然后遍历:- 提取下层 namespace 里
/proc/[cont_pid]/sched
里的 PID - 如果和
host_pid
一样,则cont_pid
就是答案
- 提取下层 namespace 里
下面是脚本:
|
|
上面这个方法是受到 jattach 项目的这个 issue 和这个 commit 的启发。
方法二
利用 procfs 的 /proc/[pid]/maps
伪文件来匹配查找。
具体原理是,只要两个 PID 实际指向的是同一个进程,那么 /proc/[pid]/maps
文件就应该是一样的,因为这个文件记录了进程的内存映射信息。
具体步骤:
- 进入
host_pid
的 namespace - 用 ps 列出这个 namespace 下所有的 PID,下面称为
cont_pid
,然后遍历:- 在 root namespace 里对
/proc/[host_pid]/maps
计算 md5sum - 在下层 namespace 里对
/proc/[cont_pid]/maps
计算 md5sum - 比较两者的结果,如果一样,则
cont_pid
就是答案
- 在 root namespace 里对
下面是脚本:
|
|
这个方法有两个点要注意:
- 是否会出现两个不同的进程
/proc/[pid]/maps
一样的情况,这个以我目前的知识来说,不能完全排除这种可能性。 /proc/[pid]/maps
是随时变化的,在上面的脚本里实际上对同一个进程的/proc/[pid]/maps
做了两次 md5sum,因此可能会出现匹配不到的情况。
评论