PID_NAMESPACES - Linux手册页

时间:2019-08-20 18:02:00  来源:igfitidea点击:

Linux程序员手册 第7部分
更新日期: 2020-06-09

名称

pid_namespaces-Linux PID名称空间概述

说明

有关名称空间的概述,请参见namespaces(7)。

PID名称空间隔离了进程ID号空间,这意味着不同PID名称空间中的进程可以具有相同的PID。 PID名称空间允许容器提供功能,例如暂停/恢复容器中的进程集,以及将容器迁移到新主机,而容器中的进程保持相同的PID。

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

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

The namespace init process

在新名称空间中创建的第一个进程(即,使用带有CLONE_NEWPID标志的clone(2)创建的进程,或使用CLONE_NEWPID标志调用unshare(2)之后的进程创建的第一个子进程)具有PID 1,并且是名称空间的" init"过程(请参阅init(1))。该进程成为孤立的所有子进程的父进程,因为驻留在此PID名称空间中的进程已终止(有关更多详细信息,请参见下文)。

如果PID名称空间的"初始化"进程终止,则内核会通过SIGKILL信号终止名称空间中的所有进程。此行为反映了以下事实:"初始"过程对于PID名称空间的正确操作至关重要。在这种情况下,到此PID名称空间的后续fork(2)失败,错误为ENOMEM;无法在其" init"进程已终止的PID名称空间中创建新进程。例如,当某个进程使用一个/ proc / [pid] / ns / pid文件的打开文件描述符时,就会发生这种情况,该描述符对应于在" init"之后将名称设置为setns(2)进入该命名空间的进程。程序已终止。调用unshare(2)之后可能发生另一种情况:如果随后由fork(2)创建的第一个子级终止,则随后对fork(2)的调用将因ENOMEM失败。

PID名称空间的其他成员只能将已为其" init"过程建立了信号处理程序的信号发送到" init"过程。此限制甚至适用于特权进程,并防止PID名称空间的其他成员意外杀死" init"进程。

同样,祖先名称空间中的进程可以-(根据kill(2)中描述的常规权限检查)-仅在" init"进程已建立子PID命名空间的" init"进程时才发送信号该信号的处理程序。 (在处理程序中,sigaction(2)中描述的siginfo_t si_pid字段将为零。)SIGKILL或SIGSTOP被特殊对待:当从祖先PID名称空间发送时,这些信号被强制传递。这些信号均不能被"初始化"过程捕获,因此将导致与这些信号相关联的常规操作(分别终止和停止该过程)。

从Linux 3.4开始,reboot(2)系统调用将导致信号发送到名称空间" init"进程。有关更多详细信息,请参见reboot(2)。

Nesting PID namespaces

PID名称空间可以嵌套:每个PID名称空间都有一个父级,但初始("根")PID名称空间除外。 PID名称空间的父级是使用clone(2)或unshare(2)创建名称空间的进程的PID名称空间。因此,PID名称空间形成一棵树,所有名称空间最终都将其祖先追溯到根名称空间。从Linux 3.7开始,内核将PID名称空间的最大嵌套深度限制为32。

一个进程对于其PID命名空间中的其他进程以及返回到根PID命名空间的每个直接祖先PID命名空间中的进程都是可见的。在这种情况下,"可见"表示一个进程可以是另一进程使用指定进程ID的系统调用进行操作的目标。相反,子PID名称空间中的进程看不到父以及进一步删除的祖先名称空间中的进程。更简洁地说:一个进程只能看到包含在其自己的PID名称空间及其后代中的进程(例如,使用kill(2)发送信号,使用setpriority(2)设置漂亮的值等)。

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

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

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

NS_GET_PARENT ioctl(2)操作可用于发现PID名称空间之间的父母关系。参见ioctl_ns(2)。

setns(2) and unshare(2) semantics

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

换句话说,创建进程时将确定进程的PID名称空间成员身份,此后不能更改。除其他外,这意味着进程之间的父级关系反映了PID名称空间之间的父级关系:进程的父级位于同一名称空间中或位于直接父PID命名空间中。

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

Adoption of orphaned children

当子进程成为孤立进程时,它将被重新关联到其父进程的PID名称空间中的" init"进程(除非父进程的较近祖先之一使用prctl(2)PR_SET_CHILD_SUBREAPER命令将自身标记为孤立后代的收割者)流程)。请注意,由于上述setns(2)和unshare(2)的语义,这可能是PID命名空间中的" init"过程,而该过程是孩子的PID名称空间的父级,而不是孩子的PID名称空间的" init"过程自己的PID名称空间。

Compatibility of CLONE_NEWPID with other CLONE_* flags

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

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

/proc and PID namespaces

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

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

从外壳程序,挂载/ proc的命令是:

$ mount -t proc proc /proc

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

/proc files

/proc/sys/kernel/ns_last_pid(since Linux 3.3)
该文件(每个PID名称空间已虚拟化)显示此PID名称空间中分配的最后一个PID。分配下一个PID时,内核将搜索大于该值的最低未分配PID,随后读取此文件时,它将显示该PID。
该文件可由拥有PID名称空间的用户名称空间内具有CAP_SYS_ADMIN功能的进程写入。这样就可以确定分配给在此PID名称空间内创建的下一个进程的PID。

Miscellaneous

当进程ID通过UNIX域套接字传递到另一个PID名称空间中的进程时(请参见unix(7)中对SCM_CREDENTIALS的描述),它将被转换为接收进程的PID名称空间中的相应PID值。

遵循规范

命名空间是特定于Linux的功能。

示例

参见user_namespaces(7)。

另外参见

clone(2),reboot(2),setns(2),unshare(2),proc(5),功能(7),凭据(7),mount_namespaces(7),名称空间(7),user_namespaces(7), switch_root(8)

出版信息

这个页面是Linux手册页项目5.08版的一部分。有关项目的说明、有关报告错误的信息以及此页面的最新版本,请访问https://www.kernel.org/doc/man-pages/