技术解析

Linux 中 Pid 和 Mnt 命名空间重用的问题
0
2021-06-22 10:48:24
idczone
1、我运行了一个进程使用了新的六个命名空间,然后把 /proc/进程号 /ns 下面的六个命名空间 Mount (防止进程关闭后这些文件被删)了,然后关闭,进程但是不知道为什么 Mount 没报错,但是 mnt (即 mount namespace )没有被 Mount......
2、我使用 Mount 上的命名空间新建进程,发现其他命名空间可以,但是使用 Pid 命名空间时,无法创建新进程,估计是因为,Pid 命名空间里没有 Pid 1 了,所以我想问怎么重用 Pid 命名空间(在创建这个空间的进程已经关闭的情况下)
换句话说怎么能够让一个进程成为 Pid 命名空间的 1 号进程(在所有 Pid 命名空间里的进程都关闭的情况下)?

怎么才能把这个 Pid 命名空间重新运行起来?

难道 pid namespace 的 1 号进程关了就不能用了?

是不是 init 进程结束 pid namespace 就销毁了??????那 docker stop、start 后 pid namespace 不变意味着 docker 不关 init 进程???????

根据文档( man 9 namespaces ),你无法把一个已经存在的进程变成 PID1,只能在 setns 之后用 clone 或者 fork 创建 PID 为 1 的新进程。

fork 可以指定进程号吗?

如果只 fork 的话 cannot allocate memory

如果 PID namespace 中的 init 进程被 kill 掉(SIGKILL),内核会给该 init 的所有其它进程发送 SIGKILL。当 init 结束时,PID namespace 也会被释放,但是也有例外,如果 /proc//ns/pid 被 bind mounted 或者其它进程打开,PID namespace 不会被释放,但是不通过 setns 将新的进程加入到该 PID namespace。
那么问题来了这个 PID namespace 还有救么?

可以不被销毁不?

有点乱。大致思路是 你要先用 setns 把当前进程加入到一个 PID namespace,再调用 fork 或者 clone,这样新进程就被加入新的 PID namespace 了。细节性的东西我得回去翻一下文档。

PID 1 退出通常意味着 PID namespace 被释放了,类似于电脑关机了。
docker 有一个后台进程( docker daemon )不退出,但是它本身不是 container 里的 PID 1。container 里的 PID 1 是由用户指定的(通过 dockerfile 里的 entrypoint 和 cmd 指令)

我使用 docker stop 命令发现 container 的进程没了,然后再 docker start 发现 container 的 pid namespace 还是同一个。按理说 pid 1 已经关过了,那 docker 是怎么重用这个 pid namespace 的呢?

甚至于我关闭 docker 以后重启还是同一个 pid ns,除非我关机

docker 没有重用 PID namespace,而是重启了一个新的。

但我自己实现时关闭 pid1 后 pid ns 就不能新建进程但是能 setns,

但是 pid namespace 是一样的啊,就是 ls -l /proc/1/ns,发现还是同一个 pid ns

对了,大佬还有我去 mount 命名空间只有 mnt ns 没有 mount 上且没有报错,为什么啊? pid 的问题我能理解但解决不了,mnt 的问题我都不知道为什么......

那可能只是 inode 号被重用了而已,你多执行几次看看,会发现数字会变化,并不是同一个 PID namespace.
关于 mount namespace 的问题,我没有看懂,还请重新描述一遍。

就是为将 /proc/进程号 /ns 里面的文件不在进程结束时被销毁,使用 mount 命令挂载到其他文件上,但是只有 mnt 文件没有被挂载上,也不能 setns......

报错 mount: wrong fs type, bad option, bad superblock on /proc/14422/ns/mnt,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail or so.

是的,pid namespace 里面的 init 进程如果退出,这个 namespace 就用不了了。这点和其他 namespace 行为不一样,因为 init 进程在 pid namespace 里面有特殊作用

那为什么 setns 无法设置 mnt namespace,这又是为什么......

最近折腾过 flatpak,你试试 unprivileged user namespaces kernel.unprivileged_userns_clone


看了 docker 的实现,终于知道为什么加载不了 mnt ns 了,是 golang 的锅......但是 mount --bind /proc/22752/ns/mnt namespace/test/mnt 还是会报错,不知道为什么 mnt 不能被 mount,其他都可以,可能有什么奇奇怪怪的机制吧

发现全是 Golang 的锅,现在只有一个问题了,为什么 mount --bind /proc/22752/ns/mnt namespace/test/mnt 会报错.......报错:mount: wrong fs type, bad option, bad superblock on /proc/22752/ns/mnt,missing codepage or helper program, or other error

应该是 propagation flag 造成的问题。
建议你参考一下"man unshare" 给出的示例:
mount --bind /root/namespaces /root/namespaces
mount --make-private /root/namespaces
touch /root/namespaces/mnt
unshare --mount=/root/namespaces/mnt
换句话讲,你的 namespace/test/mnt 文件所属的 mounting point 的 propagation flag 必须是 private.

的确是这个问题

数据地带为您的网站提供全球顶级IDC资源
在线咨询
专属客服