pid_namespace学习笔记


PID命名空间隔离的意义

PID 命名空间的隔离作用非常关键,主要体现在以下几个方面:

  • 进程树的独立性:每个容器或命名空间有独立的进程 ID,从 1 开始,确保进程间互不干扰。
  • 安全性和隔离性:通过进程 PID 隔离,确保容器和宿主机之间的进程管理不会发生冲突,从而提升容器环境的安全性。
  • 简化容器管理和监控:容器中的进程管理完全独立,使得容器可以像虚拟机一样独立进行监控、管理和生命周期管理。
  • 实现虚拟化资源隔离:PID 命名空间为容器化、虚拟化环境提供进程层面的资源隔离,使得多个容器或虚拟机能够共享同一台物理机器而不互相干扰。

综上所述,PID 命名空间是实现 容器化和虚拟化 环境中 进程隔离资源管理 的基础,它为每个容器或虚拟机提供了独立的进程树和 PID 管理,极大增强了系统的安全性和资源利用效率。

进程的pid_namespace结构

进程创建

进程创建时函数调用栈如下:

根据flags判断是否要创建新的namespace,如果不需要,就直接copy父进程的namespace,也就是父进程的task中的nsproxy成员:

……

看一下get_nsproxy函数,就是简单地将父进程的nsproxy引用计数加一:

如果需要创建新的namespace则要调用create_new_namespace函数,首先创建一个新的namespace叫做new_nsp:

new_nsp的pid_ns_for_children成员通过调用copy_pid_ns来获得:

下面看这个函数,直接看create_pid_namespace:

create_pid_namespace函数如下所示,首先分配一个空的ns,然后ns的level就是父进程ns的level+1,然后引用计数则设定为1:

因此新建namespace过程如下:

getpid过程分析

https://elixir.bootlin.com/linux/v6.13.5/source/kernel/sys.c

先进性源码分析,一路跟进:

可以看到前面的task_pid_ptr和rcu_dereference应该就是从task中得到当前进程的pid结构体,

其过程图示如下:

struct pid到底是干什么的

struct pid的定义如下:https://elixir.bootlin.com/linux/v6.13.5/source/include/linux/pid.h#L55

upid定义如下:

看一下何时分配它的,首先定位到copy_process函数中,https://elixir.bootlin.com/linux/v6.13.5/source/kernel/fork.c#L2149,其参数会传入一个pid(经过查看内核源码中仅有的三处引用可以发现,有一处为init_struct_pid,其余两处都是NULL):

之后会有这样的处理:

让我们跟进到alloc_pid函数中https://elixir.bootlin.com/linux/v6.13.5/source/kernel/pid.c#L166,首先是分配空间并设置level:

之后是一个for循环:

在for循环中会计算出一个nr,似乎是在每一层的pid_namespace中给当前进程分配一个pid:

然后在pid的numbers数组中设置:

退出for循环之后,设置引用计数为1,然后倒序遍历pid的numbers数组替换nr?:

回到copy_process函数后设置task的pid为pid_nr(pid):

pid的refcount是干嘛的

参考

https://zhuanlan.zhihu.com/p/335171876


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录