Linux Namespaces in operation记录 - part 4

20 篇文章 0 订阅
14 篇文章 0 订阅


:本文绝大部分内容来自 LinuxNamespaces实践part4 ,原文 系列文章详细描述了 Linux Namespace相关内容,英语过关的建议阅读原文,本文内容主要用来记录学习内容,如有不当之处还请评论区指正。

PID Namespace

一个新创建的PID Namespace中的第一个进程的ID为1,这个进程同时也是该Namespace中的初始化(init)进程,需要承担回收孤儿进程等任务。

一个例子

  • ns_child_exec.c 在新的Namespace中执行simple_init.c
  • simple_init.c 新Namespace中的init进程,回收孤儿进程
  • orphan.c 一个孤儿进程示例
    上述三个程序组成了这个示例,在ns_child_exec.c程序中调用clone函数创建子进程并设置Namespace标志。子进程运行simple_init.c程序,该程序会模拟一个终端,调用execvp命令执行输入的程序。在这个“终端”中执行orphan程序,可以看到orphan的父进程结束后,子进程成为孤儿进程并且被simple_init回收。代码ns_child_exec.c, simple_init.c, orphan.c,代码中的英文注释解释了处理SIGTTOU信号、设置终端前台进程组等的原因。
    上述程序的执行结果如下:
root@jeffrey: /Coding/namespace# ./ns_child_exec -pmv ./simple_init -v
./ns_child_exec: PID of child created by clone() is 545
        init: my PID is 1
init$ ./orphan
        init: created child 2
Parent (PID=2) created child with PID 3
Parent (PID=2; PPID=1) terminating
        init: SIGCHLD handler: PID 2 terminated
init$
Child (PID=3) now an orphan (parent PID=1)
Child (PID=3) terminating
        init: SIGCHLD handler: PID 3 terminated


init$ ps
        init: created child 4
  PID TTY          TIME CMD
  240 tty2     00:00:00 init
  526 tty2     00:00:00 sudo
  527 tty2     00:00:00 su
  528 tty2     00:00:00 bash
  544 tty2     00:00:00 ns_child_exec
  545 tty2     00:00:00 simple_init
  548 tty2     00:00:00 ps
        init: SIGCHLD handler: PID 4 terminated
init$ mount -t proc proc /proc
        init: created child 5
        init: SIGCHLD handler: PID 5 terminated
init$ ps
        init: created child 6
  PID TTY          TIME CMD
    1 tty2     00:00:00 simple_init
    6 tty2     00:00:00 ps
        init: SIGCHLD handler: PID 6 terminated
init$ ^C./ns_child_exec: terminating
root@jeffrey: /Coding/namespace# 

上述shell命令及输出结果展示了该程序的使用

  • -pmv参数表示创建新的PID NamespaceMount Namespace,并打印日志信息
  • 日志信息init: my PID is 1表明simple_init程序成为了新PID Namespaceinit进程
  • 执行orphan程序后simple_init打印了两条SIGCHLD信号处理日志,表明孤儿进程也被它回收了
  • ps命令依赖/proc中的信息,故若要在执行ps显示当前PID Namespace的程序,需要显式挂载它
    • 创建Namespace时需指定创建新Mount NamespacePID Namespace,如-pmv参数
    • 可以通过mount -t proc proc /proc命令挂载
    • 或通过mount("proc", "/proc", "proc", 0, NULL)函数挂载

init进程与信号

linux中的init进程:

  • 只处理设置了处理程序的信号
  • 不会被其它程序或用户(包括superuser)kill

PID Namespace中的init进程:

  • 类似的,在该Namespace中只会收到设置了处理程序的信号
  • 内核产生的信号依然会发送给init进程,如硬件异常等
  • 对于来自祖先PID Namespace的信号,init进程会收到设置了处理程序的信号+SIGKILL+SIGSTOP
  • SIGKILL(来自祖先)kill后,所有子进程都会被kill

一般来讲,一个PID Namespace的所有进程都被终止后,这个PID Namespace也会被销毁,然而有一个特例:若/proc/PID/ns/pid文件处于bind mounted或打开状态,则该PID Namespace不会被销毁。不过,这种情况下无法再在该PID Namespace中创建新的进程(通过setns()+fork()),实际上当执行fork时会失败并产生ENOMEM错误。

unshare() 与 setns()

unshare(CLONE_NEWPID);

fd = open("/proc/PID/ns/pid", O_RDONLY);
setns(fd, 0);

通过在unshare(int flags)的参数中指定CLONE_NEWPID可以创建一个新PID Namespace,调用unshare进程本身不会加入到新PID Namespace中,但由该进程创建的子进程都会被加入其中。其原因在于,几乎Linux程序包括GNU等都认为进程标识PID是不变的,若改变当前进程的PID,则许多依赖于此的函数都将无法使用了。

setns(int fd, int nstype)同样支持PID Namespacefd参数为一个PID Namespace的文件描述符,该PID Namespace应为调用进程的PID Namespace的后代。相应文件描述符fd可以通过打开/proc/PID/ns/pid文件获得。与unshare类似,setns同样不会讲调用进程移动到新的PID Namespace,而是将其子进程放入其中。

又一个例子

本示例展示了setns的使用,使用上一个例子创建一个新的PID Namespace并运行simple_init模拟终端,之后我们在另一个终端中运行ns_run程序,设置子进程的PID Namespacesimple_init的相同,然后创建一个子进程。示例程序,如下为终端的运行结果。
terminal a:

root@jeffrey: /Coding/namespace# clear
root@jeffrey: /Coding/namespace# ./ns_child_exec -p ./simple_init -v
        init: my PID is 1
init$   init: SIGCHLD handler: PID 4 terminated

terminal b:

root@jeffrey: /Coding/namespace# ps -C simple_init
  PID TTY          TIME CMD
  601 tty3     00:00:00 simple_init
root@jeffrey: /Coding/namespace# ./ns_run -f -n /proc/601/ns/pid ./orphan
Parent (PID=3) created child with PID 4
Parent (PID=3; PPID=0) terminating
root@jeffrey: /Coding/namespace#
Child (PID=4) now an orphan (parent PID=1)
Child (PID=4) terminating

root@jeffrey: /Coding/namespace# 

首先在终端a中执行./ns_child_exec -p ./simple_init -v,之后再终端b中执行./ns_run -f -n /proc/601/ns/pid ./orphan,其中601为simple_init程序的PID。可以看到,orphan程序创建了孤儿进程PID=4,该进程被simple_init回收了,同时orphan的输出Parent (PID=3; PPID=0)也表明它在与simple_init相同的Namespace中执行了,因而无法看到位于ns_runNamespace中的父进程表示PPID=0。下图表明了上述代码的关系:

小结

本文主要讲述了PID Namespaceinit进程的角色、unsharesetns等内容,感兴趣的同学可以阅读原文获得更多相关内容。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值