简介

Linux `Namespace`提供了一种内核级别隔离系统资源的办法,通过将零碎的全局资源放在不同的`Namespace`中,来实现资源隔离的目标。不同`Namespace`的程序,能够享有一份独立的系统资源。目前Linux中提供了六类系统资源的隔离机制,别离是:
  • Mount: 隔离文件系统挂载点
  • UTS: 隔离主机名和域名信息
  • IPC: 隔离过程间通信
  • PID: 隔离过程的ID
  • Network: 隔离网络资源
  • User: 隔离用户和用户组的ID

上面简略的介绍一下这些Namespace的应用和性能。

应用

波及到`Namespace`的操作接口包含`clone()`、`setns()`、`unshare()`以及还有`/proc`下的局部文件。为了应用特定的`Namespace`,在应用这些接口的时候须要指定以下一个或多个参数:
  • CLONE_NEWNS: 用于指定Mount Namespace
  • CLONE_NEWUTS: 用于指定UTS Namespace
  • CLONE_NEWIPC: 用于指定IPC Namespace
  • CLONE_NEWPID: 用于指定PID Namespace
  • CLONE_NEWNET: 用于指定Network Namespace
  • CLONE_NEWUSER: 用于指定User Namespace

上面简略概述一下这几个接口的用法。

clone零碎调用

能够通过clone零碎调用来创立一个独立Namespace的过程,它的函数形容如下:

int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);

它通过flags参数来管制创立过程时的个性,比方新创建的过程是否与父过程共享虚拟内存等。比方能够传入CLONE_NEWNS标记使得新创建的过程领有独立的Mount Namespace,也能够传入多个flags使得新创建的过程领有多种个性,比方:

flags = CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC;

传入这个flags那么新创建的过程将同时领有独立的Mount NamespaceUTS NamespaceIPC Namespace

通过/proc文件查看已存在的Namespace

在3.8内核开始,用户能够在/proc/$pid/ns文件下看到本过程所属的Namespace的文件信息。例如PID为2704过程的状况如下图所示:

其中4026531839是Namespace的ID,如果两个过程的Namespace ID雷同表明过程同处于一个命名空间中。
这里须要留神的是:只/proc/$pid/ns/对应的Namespace文件被关上,并且该文件描述符存在,即便该PID所属的过程被销毁,这个Namespace会仍然存在。能够通过挂载的形式关上文件描述符:

touch ~/mntmount --bind /proc/2704/mnt ~/mnt

这样就能够保留住PID为2704的过程的Mount Namespace了,即便2704过程被销毁或者退出,ID为4026531840的Mount Namespace仍然会存在。

setns退出已存在的Namepspace

setns()函数能够把过程退出到指定的Namespace中,它的函数形容如下:

int setns(int fd, int nstype);

它的参数形容如下:

  • fd参数:示意文件描述符,后面提到能够通过关上/proc/$pid/ns/的形式将指定的Namespace保留下来,也就是说能够通过文件描述符的形式来索引到某个Namespace
  • nstype参数:用来查看fd关联Namespace是否与nstype表明的Namespace统一,如果填0的话示意不进行该项查看。

通过在程序中调用setns来将过程退出到指定的Namespace中。

unshare脱离到新的Namespace

unshare()零碎调用用于将以后过程和所在的Namespace拆散,并退出到一个新的Namespace中,绝对于setns()零碎调用来说,unshare()不必关联之前存在的Namespace,只须要指定须要拆散的Namespace就行,该调用会主动创立一个新的Namespace
unshare()的函数形容如下:

int unshare(int flags);

其中flags用于指明要拆散的资源类别,它反对的flagsclone零碎调用反对的flags相似,这里简要的叙述一下几种标记:

  • CLONE_FILES: 子过程个别会共享父过程的文件描述符,如果子过程不想共享父过程的文件描述符了,能够通过这个flag来勾销共享。
  • CLONE_FS: 使以后过程不再与其余过程共享文件系统信息。
  • CLONE_SYSVSEM: 勾销与其余过程共享SYS V信号量。
  • CLONE_NEWIPC: 创立新的IPC Namespace,并将该过程退出进来。

注意事项

这里须要留神的是unshare()setns()零碎调用对PID Namespace的解决不太雷同,当unshare PID namespace时,调用过程会为它的子过程调配一个新的PID Namespace,然而调用过程自身不会被移到新的Namespace中。而且调用过程第一个创立的子过程在新Namespace中的PID为1,并成为新Namespace中的init过程。
setns()零碎调用也是相似的,调用者过程并不会进入新的PID Namespace,而是随后创立的子过程会进入。
为什么创立其余的Namespace时unshare()setns()会间接进入新的Namespace,而唯独PID Namespace不是如此呢?
因为调用getpid()函数失去的PID是依据调用者所在的PID Namespace而决定返回哪个PID,进入新的PID namespace会导致PID产生变动。而对用户态的程序和库函数来说,他们都认为过程的PID是一个常量,PID的变动会引起这些过程奔溃。
换句话说,一旦程序过程创立当前,那么它的PID namespace的关系就确定下来了,过程不会变更他们对应的PID namespace。

小结

通过下面简略的概述,对于Namespace的操作有以下形式:

  • 1、能够在过程刚创立的时候通过clone零碎调用为新过程调配一个或多个新的Namespace
  • 2、通过setns()将过程退出到已有的Namespace中。
  • 3、通过unshare()为已存在的过程创立一个或多个新的Namespace

接下来具体的介绍一下各个Namespace的性能和个性。

Mount Namespace

Mount Namespace用来隔离文件系统的挂载点,不同Mount Namespace的过程领有不同的挂载点,同时也领有了不同的文件系统视图。Mount Namespace是历史上第一个反对的Namespace,它通过CLONE_NEWNS来标识的。

挂载的概念

挂载的过程是通过mount零碎调用实现的,它有两个参数:一个是已存在的一般文件名,一个是能够间接拜访的非凡文件,一个是非凡文件的名字。这个非凡文件个别用来关联一些存储卷,这个存储卷能够蕴含本人的目录层级和文件系统构造。
mount所达到的成果是:像拜访一个一般的文件一样拜访位于其余设施上文件系统的根目录,也就是将该设施上目录的根节点挂到了另外一个文件系统的页节点上,达到给这个文件系统裁减容量的目标。
能够通过/proc文件系统查看一个过程的挂载信息,具体做法如下:

cat /proc/$pid/mountinfo

其输入后果如下:

其中输入的格局如下:

挂载流传

过程在创立Mount Namespace时,会把以后的文件构造复制给新的Namespace,新的Namespace中的所有mount操作仅影响本身的文件系统。但随着引入挂载流传的个性,Mount Namespace变得并不是齐全意义上的资源隔离,这种流传个性使得多Mount Namespace之间的挂载事件能够相互影响。
挂载流传定义了挂载对象之间的关系,零碎利用这些关系来决定挂载对象中的挂载事件对其余挂载对象的影响。其中挂载对象之间的关系形容如下:

  • 共享关系(MS_SHARED):一个挂载对象的挂载事件会跨Namespace共享到其余挂载对象。
  • 从属关系(MS_SLAVE): 流传的方向是单向的,即只能从Master流传到Slave方向。
  • 公有关系(MS_PRIVATE): 不同Namespace的挂载事件是互不影响的(默认选项)。
  • 不可绑定关系(MS_UNBINDABLE): 一个不可绑定的公有挂载,与公有挂载相似,然而不能执行挂载操作。

其中给挂载点设置挂载关系的例子如下:

mount --make-shared /mntS      # 将挂载点设置为共享关系属性 mount --make-private /mntP     # 将挂载点设置为公有关系属性 mount --make-slave /mntY       # 将挂载点设置为从属关系属性 mount --make-unbindable /mntU  # 将挂载点设置为不可绑定属性

留神在设置公有关系属性时,在本命名空间下的这个挂载点是Slave,而父命名空间下这个挂载点是Master,挂载流传的方向只能由Master传给Slave。

绑定挂载

绑定挂载的引入使得mount的其中一个参数不肯定要是一个非凡文件,也能够是该文件系统上的一个一般文件目录。Linux中绑定挂载的用法如下:

mount --bind /home/work /home/alphamount -o bind /home/work /home/alpha

其中/home/work是磁盘上的存在的一个目录,而不是一个文件设施(比方磁盘分区)。如果须要将Linux中两个文件目录链接起来,能够通过绑定挂载的形式,挂载后的成果相似于在两个文件目录上建设了硬链接。
在绑定挂载中同时会波及到挂载的流传个性,挂载流传的个性参考:Linux绑定挂载

UTS Namespace

UTS Namespace提供了主机名和域名的隔离,也就是struct utsname里的nodenamedomainname两个字段。不同Namespace中能够领有独立的主机名和域名。
那么为什么须要对主机名和域名进行隔离呢?因为主机名和域名能够用来代替IP地址,如果没有这一层隔离,同一主机上不同的容器的网络拜访就可能出问题。

IPC Namespace

IPC Namespace是对过程间通信的隔离,过程间通信常见的办法有信号量、音讯队列和共享内存。IPC Namespace次要针对的是SystemV IPC和Posix音讯队列,这些IPC机制都会用到标识符,比方用标识符来辨别不同的音讯队列,IPC Namespace要达到的指标是雷同的标识符在不同的Namepspace中代表不同的通信介质(比方信号量、音讯队列和共享内存)。
原文

更多深度文章,关注:二进制社区