[linux语法手册中文版]-PID_NAMESPACES(7)

名称:

        pid_namespaces

描述:

        如果要看namespaces的概述,去看namespaces(7).

        PID 命名空间隔离了进程 ID 号空间,这意味着不同 PID 命名空间中的进程可以具有相同的 PID。 PID 命名空间允许容器提供功能,例如挂起/恢复容器中的一组进程并将容器迁移到新主机,同时容器内的进程保持相同的 PID。

        新 PID 命名空间中的 PID 从 1 开始,有点像独立系统,调用 fork(2)、vfork(2) 或 clone(2) 将生成具有命名空间内唯一 PID 的进程。

        使用 PID 命名空间需要使用 CONFIG_PID_NS 选项配置的内核。

namespace初始化进程:

        在新命名空间中创建的第一个进程(即,使用带有 CLONE_NEWPID 标志的 clone(2) 创建的进程,或在使用 CLONE_NEWPID 标志调用 unshare(2) 之后由进程创建的第一个子进程)的PID为1, 并且是命名空间的“init”进程(参见 init(1))。 由于驻留在此 PID 命名空间中的进程终止(有关更多详细信息,请参见下文),此进程成为孤立的任何子进程的父进程。

        如果一个PID命名空间的“init”进程终止了,那么内核会通过SIGKILL信号终止这个命名空间中的所有进程。这个行为反映了这样一个事实,即“init”进程对于 PID 命名空间的正确操作至关重要。在这种情况下,随后进入此 PID 命名空间的 fork(2) 失败并显示错误 ENOMEM; 无法在“init”进程已终止的 PID 命名空间中创建新进程。这种情景可能发生在,比如,当一个进程使用一个打开的文件描述符来处理 /proc/[pid]/ns/pid 文件时,该文件对应于一个利用setns()从一个命名空间进入那个“init”进程结束的命名空间的进程。在调用 unshare(2) 之后可能会发生另一种可能的情况:如果随后由 fork(2) 创建的第一个子进程终止,则对 fork(2) 的后续调用将失败并显示 ENOMEM。

        PID namespace的其他成员只能将“init”进程已经为其建立信号处理程序的信号发送到“init”进程。 此限制甚至适用于特权进程,并防止 PID namespace的其他成员意外终止“init”进程。

        同样,祖先命名空间中的进程可以(根据 kill(2) 中描述的通常权限检查)向子 PID 命名空间的“init”进程发送信号,前提是“init”进程已为该信号建立了处理程序 . (在处理程序中,sigaction(2) 中描述的 siginfo_t si_pid 字段将为零。)SIGKILL 或 SIGSTOP 的处理方式比较特殊:这些信号在从祖先 PID 命名空间发送时被强制传递。 这些信号都不能被“init”进程捕获,因此将导致与这些信号相关的通常操作(分别是终止和停止进程)。

嵌套PID namespaces:

        PIDnamespaces可以嵌套:除了root PID namespace,每个PID namespace都有一个parent,就是调用clone(2)或者unshare(2)创建它的那个进程的PID命名空间。因此PIDnamespace形成了一棵树,能追溯到它的祖先一直到root。Linux3.7之后,内核限制了PID namespaces的最大嵌套深度为32。

        进程对其 PID 命名空间中的其他进程以及每个直接祖先 PID 命名空间一直到根命名空间中的进程都可见。在这种情况下,“可见”意味着一个进程可以成为另一个进程使用指定进程 ID 的系统调用的操作目标。 相反,子 PID 命名空间中的进程无法看到父命名空间和进一步删除的祖先命名空间中的进程。 更简洁地说:进程只能看到(例如,使用 kill(2) 发送信号,使用 setpriority(2) 设置好值等)仅包含在其自己的 PID 命名空间和该命名空间的后代中的进程。

        进程在 PID 命名空间层次结构的每一层中都有一个进程 ID,其中可见,并通过每个直接祖先命名空间返回到根 PID 命名空间。 对进程 ID 进行操作的系统调用始终使用在调用者的 PID 命名空间中可见的进程 ID 进行操作。 对 getpid(2) 的调用始终返回与创建进程的命名空间关联的 PID。

        PID 命名空间中的某些进程可能具有在命名空间之外的父进程。 例如,命名空间中初始进程的父进程(即 PID 为 1 的 init(1) 进程)必然位于另一个命名空间中。 同样,使用 setns(2) 使其子进程加入 PID 命名空间的进程的直接子进程与 setns(2) 的调用者位于不同的 PID 命名空间中。 为此类进程调用 getppid(2) 返回 0。

        虽然进程可以自由地进入子 PID 命名空间(例如,使用带有 PID 命名空间文件描述符的 setns(2)),但它们可能不会向另一个方向移动。 也就是说,进程不能进入任何祖先命名空间(父、祖父等)。 更改 PID 命名空间是一种单向操作。

setns(2)和unshare(2)语义

        调用 setns(2) 指定一个 PID 命名空间文件描述符,并调用带有 CLONE_NEWPID 标志的 unshare(2) 会导致调用者随后创建的子级被放置在与调用者不同的 PID 命名空间中。 (自 Linux 4.12 起,PID 命名空间通过 /proc/[pid]/ns/pid_for_children 文件显示,如 namespaces(7) 中所述。)但是,这些调用不会更改调用进程的 PID 命名空间,因为 这样做会改变调用者对其自己 PID 的想法(如 getpid() 报告的那样),这会破坏许多应用程序和库。

        换句话说:进程的 PID 命名空间成员资格在进程创建时确定,此后无法更改。 除此之外,这意味着进程之间的父级关系反映了 PID 命名空间之间的父级关系:进程的父级要么位于同一命名空间中,要么驻留在直接父 PID 命名空间中。

        进程只能调用带有 CLONE_NEWPID 标志的 unshare(2) 一次。 执行此操作后,其 /proc/PID/ns/pid_for_children 符号链接将为空,直到在命名空间中创建第一个子项。

回收孤儿子进程

        当一个子进程成为孤儿时,它会被重新分配到其父进程的 PID 命名空间中的“init”进程(除非父进程的近亲之一使用 prctl(2) PR_SET_CHILD_SUBREAPER 命令将自己标记为孤儿后代的收割者 进程)。 请注意,由于上述 setns(2) 和 unshare(2) 语义,这可能是 PID 命名空间中的“init”进程,它是子进程 PID 命名空间的父进程,而不是子进程中的“init”进程 自己的PID命名空间。

CLONE_NEWPID 与其他 CLONE_* 标志的兼容性

        在当前版本的 Linux 中,CLONE_NEWPID 不能与 CLONE_THREAD 结合使用。 线程需要位于相同的 PID 命名空间中,以便进程中的线程可以相互发送信号。 同样,必须可以在 proc(5) 文件系统中看到进程的所有线程。 此外,如果两个线程在不同的 PID 命名空间中,则发送信号的进程的进程 ID 无法在发送信号时进行有意义的编码(请参阅 sigaction(2) 中对 siginfo_t 类型的描述)。 由于这是在信号入队时计算的,因此由多个 PID 命名空间中的进程共享的信号队列将打败它。

        在早期版本的 Linux 中,CLONE_NEWPID 与 CLONE_SIGHAND(Linux 4.3 之前的版本)以及 CLONE_VM(Linux 3.12 之前的版本)结合使用是另外禁止的(失败并出现错误 EINVAL)。 解除这些限制的更改也已移植到早期的稳定内核中。

/proc 和PID namespace

        /proc 文件系统(在 /proc/[pid] 目录中)仅显示在执行 MOUNT 的进程的 PID 命名空间中可见的进程,即使 /proc 文件系统是从其他命名空间中的进程查看的。

        创建新的 PID 命名空间后,子进程更改其根目录并在 /proc 上挂载新的 procfs 实例很有用,这样 ps(1) 等工具才能正常工作。 如果通过在 clone(2) 或 unshare(2) 的 flags 参数中包含 CLONE_NEWNS 来同时创建新的挂载命名空间,则无需更改根目录:可以直接通过 /proc 挂载新的 procfs 实例。

        在shell中挂载/proc的命令是:

                $ mount -t proc proc /proc

        在路径 /proc/self 上调用 readlink(2) 会在 procfs 挂载的 PID 命名空间(即挂载 procfs 的进程的 PID 命名空间)中产生调用者的进程 ID。 当进程想要在其他命名空间中发现其 PID 时,这对于内省目的很有用。

 /proc 文件

        /proc/sys/kernel/ns_last_pid

                此文件显示在此 PID 命名空间中分配的最后一个 PID。 当分配下一个 PID 时,内核将搜索大于此值的最低未分配 PID,当随后读取此文件时,它将显示该 PID。

                此文件可由在其用户命名空间内具有 CAP_SYS_ADMIN 功能的进程写入。 这使得确定分配给在此 PID 命名空间内创建的下一个进程的 PID 成为可能。

Miscellaneous

        当进程 ID 通过 UNIX 域套接字传递到不同 PID 命名空间中的进程时(请参阅 unix(7) 中 SCM_CREDENTIALS 的描述),它被转换为接收进程的 PID 命名空间中的相应 PID 值。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值