Linux操作系统中的Namespace是什么?和基本用法。namespace命名空间的概念是Linux内核用来隔离内核资源的方式。通过命名空间,一些进程只能看到与自己相关的部分资源,而另一些进程只能看到与自己相关的资源。这两组进程根本感觉不到对方的存在。具体实现方法是在同一个命名空间中指定一个或多个进程的相关资源。Linux命名空间是一种对全局系统资源的封装和隔离,使得不同命名空间中的进程拥有独立的全局系统资源。更改命名空间中的系统资源只会影响当前命名空间中的进程,而不会影响其他命名空间中的进程。.namespace的用处可能是绝大多数用户和我一样,都是在使用docker之后才开始了解linux的namespace技术的。事实上,Linux内核实现命名空间的主要目的之一就是实现轻量级的虚拟化(容器)服务。同一命名空间下的进程可以感知彼此的变化,但对外部进程一无所知。这样容器中的进程就可以有一种自己在一个独立系统中的错觉,从而达到隔离的目的。也就是说,Linux内核提供的命名空间技术为docker等容器技术的出现和发展提供了基础条件。我们可以从docker实现者的角度来考虑如何实现一个资源隔离的容器。比如能否通过chroot命令切换根目录的挂载点,隔离文件系统。为了在分布式环境中进行通信和定位,容器必须有独立的IP、端口和路由,这就需要对网络进行隔离。同时,容器还需要一个独立的主机名来在网络中标识自己。接下来需要隔离进程间通信、用户权限等。运行在容器中的应用需要一个进程ID(PID),自然需要和宿主机中的PID隔离开来。也就是说,这六种隔离能力是实现一个容器的基础。让我们看看Linux内核的命名空间特性为我们提供了什么样的隔离能力:上表中的前六个命名空间是实现容器所必需的隔离技术,至于新提供的Cgroup命名空间,目前还没有被采用码头工人。相信在不久的将来,各种容器也会加入对Cgroup命名空间的支持。命名空间的发展历史Linux在很早的版本中就实现了部分命名空间,比如2.4内核就实现了mount命名空间。大多数名称空间支持在内核2.6中完成,例如IPC、Network、PID和UTS。还有一些特殊的命名空间,比如User,从2.6内核开始实现,但在3.8内核中宣布完成。同时,随着Linux自身的发展以及容器技术不断发展带来的需求,也会支持新的命名空间。例如,Cgroup命名空间是在4.6内核中添加的。Linux提供了多种API来操作命名空间,分别是clone()、setns()和unshare()函数。为了确定哪个命名空间被隔离,在使用这些API时,通常需要指定一些调用参数:CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS和CLONE_NEWCGROUP。如果想同时隔离多个命名空间,可以使用|(按位或)组合这些参数。同时我们也可以通过/proc下的一些文件来操作namespace。下面我们就来看看这些接口的简单用法。查看进程所属的命名空间从内核版本号3.8开始,/proc/[pid]/ns目录下会包含进程所属的命名空间信息。使用如下命令查看当前进程所属的命名空间信息:$ll/proc/$$/ns首先,这些命名空间文件是链接文件。链接文件的内容格式为xxx:[inodenumber]。其中xxx是namespace的类型,inodenumber用来标识一个namespace。我们也可以理解为命名空间的ID。如果两个进程的命名空间文件指向同一个链接文件,则意味着它们相关的资源在同一个命名空间中。其次,将这些链接文件放在/proc/[pid]/ns中的另一个作用是,一旦这些链接文件被打开,只要打开的文件描述符(fd)存在,那么即使该命名空间下的所有进程都关闭了最终这个命名空间会一直存在,后续进程可以再次加入它。除了打开文件的方式,我们还可以通过挂载文件的方式来防止命名空间被删除。比如我们可以将当前进程中的uts挂载到~/uts文件中:$touch~/uts$sudomount--bind/proc/$$/ns/uts~/uts使用stat命令查看结果:很神奇,~/uts中的inode和链接文件中的inode号是一样的,是同一个文件。克隆函数我们可以在创建新进程时使用clone()来创建命名空间。C语言库中clone()的声明如下:);其实上面,clone()是C语言库中定义的一个包装函数,负责构建新进程的栈,调用对程序员隐藏的clone()系统调用。clone()其实是Linux系统调用fork()的更通用的实现,可以通过flags来控制使用多少个函数。以CLONE_开头的falg(标志位)参数有20多种,控制clone进程的方方面面(比如是否与父进程共享虚拟内存等),下面我们只介绍4个namespace相关的参数:fn:指定一个要被新进程执行的Function。当此函数返回时,子进程终止。该函数返回一个整数,表示子进程的退出代码。child_stack:传入子进程使用的栈空间,即把用户态栈指针赋给子进程的esp寄存器。调用进程(调用clone()的进程)应始终为子进程分配一个新堆栈。flags:表示哪些标志以CLONE_开头,与命名空间相关的有CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS和CLONE_NEWCGROUP。arg:指向传递给fn()函数的参数。在后续文章中,我们主要使用clone()函数来创建和演示各种类型的命名空间。setns函数可以通过setns()函数将当前进程添加到已有的命名空间中。C语言库中setns()的声明如下:#define_GNU_SOURCE#include
