本文将就namespace这个知识点,进行简单的归纳总结,力求通俗易通。在资料汇总的过程中,参考了许多网上的博客资料,在文章尾部给出相关链接。
namespace,命名空间,从名字上看,应该是类似于包含许多名字的空间,打个比方,三年一班的小明和三年二班的小明,虽说他们名字是一样的,但是所在班级不一样,那么,在全年级排行榜上面,即使出现两个名字一样的小明,也会通过各自的学号来区分。对于学校来说,每个班级就相当于是一个命名空间,这个空间的名称是班级号。班级号用于描述逻辑上的学生分组信息,至于什么学生分配到1班,什么学生分配到2班,那就由学校层面来统一调度。大致应该就是这么个意思,恩。
C++中的命名空间
命名空间这个概念不仅仅在kernel中有使用,在其他语言中也有所体现。例如在C++中,标准C++库中所包含的所有内容(包括常量、变量、结构、类和函数)都被定义在命名空间std中。我们可以定义有名命名空间,也可以定义无名命名空间,命名空间可以嵌套定义,
1: 有名的命名空间:
2:
3: namespace 命名空间名 {
4:
5: 声明序列可选
6:
7: }
8:
9: 无名的命名空间:
10:
11: namespace {
12:
13: 声明序列可选
14:
15: }
16:
在C++中,如果代码的最前面没有使用 using namespace std 的话,对于输入输出流,就必须指定所在的命名空间(std::cout <<),否则编译器会找不到他们的具体实现。可以这么说,命名空间是对全局作用域的细分。
Linux中的namespace
在Linux系统中,可以同时存在多用户多进程,那么对他们的运行协调管理,通过进程调度和进度管理可以解决,但是,整体资源是有限的,怎么把有限的资源(进程号、通信资源、网络资源等等)合理分配给各个用户所在的进程?Linux中提出了namespace机制,这是一种轻量级的虚拟化形式。再次之前,Linux中很多资源是全局管理的,例如,系统中所有进程,都是通过PID来标识的,就像每个学生的学号一样,在整个学校范围内,肯定是唯一标识这个学生的。用户的ID管理,各个用户通过全局为UID来标识,每个学校的校长也只有有一个,它的UID为0,权利最大,可以对学校内全部老师和学生发起命令。每个学生可以看到其他学生的活动,但是无权把他们赶出学校,这是可以理解的。这种集中统一的管理方式,很适合大规模人群的管理。
随着大数据、虚拟化的兴起,Linux为了提供更加精细的资源分配管理机制,给出了namespace机制解决方法。
命名空间建立系统的不同视图, 对于每一个命名空间,从用户看起来,应该像一台单独的Linux计算机一样,有自己的init进程(PID为0),其他进程的PID依次递增,A和B空间都有PID为0的init进程,子容器的进程映射到父容器的进程上,父容器可以知道每一个子容器的运行状态,而子容器与子容器之间是隔离的。
Linux中有chroot的系统调用,该方法将进程限制到文件系统的某一部分,是一种简单的命名空间机制。
在task_struct结构体中,有struct nsproxy *nsproxy 这个成员变量,
1: /*
2: * A structure to contain pointers to all per-process
3: * namespaces - fs (mount), uts, network, sysvipc, etc.
4: *
5: * ‘count‘ is the number of tasks holding a reference.
6: * The count for each namespace, then, will be the number
7: * of nsproxies pointing to it, not the number of tasks.
8: *
9: * The nsproxy is shared by tasks which share all namespaces.
10: * As soon as a single namespace is cloned or unshared, the
11: * nsproxy is copied.
12: */
13: struct nsproxy {
14: atomic_t count;
15: spinlock_t nslock;
16: struct uts_namespace *uts_ns;
17: struct ipc_namespace *ipc_ns;
18: struct mnt_namespace *mnt_ns;
19: struct pid_namespace *pid_ns;
20: };
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
uts_ns:UTS为Unix Timesharing System的简称,包含内存名称、版本、底层体系结构等信息。
ipc_ns:保存所有与进程间通讯(IPC)有关的信息。
mnt_ns: 当前装载的文件系统
pid_ns: 有关进程ID的信息
在高级版本上,还有net_ns的网络信息,user_ns的资源配额的信息等。
下面以uts命名空间为例子,介绍如何创建用户空间。
从上面的框架图可以看出,所谓的子空间,就是父进程fork一个子进程出来,然后子进程与父进程不共享某些资源,那么,就可以说,这个子进程在它自己的那个命名空间内。
要达到这种效果,就必须对fork的行为进行精确控制,内核提供的如下参数来设置:
UTS命名空间没有层次结构,所有信息都汇集到如下结构:
,kref是引用计数器,用于跟踪内核中有多少地方使用uts_namespace的实例。它提供的属性信息如下:
,从名字上,可以得知uts包含系统名称、版本号、机器名称等等。使用uname -a可以查看这些信息。
系统初始默认值保持在init/version.c 中的init_uts_ns全局变量中,在系统初始化task时,配置init_task。
用户可以在fork时,传入CLONE_NEWUTS标准,创建新的UTS命名空间。执行此操作,会生成先前uts_namespace的一份副本,当前进程内部的nsproxy指向此副本,然后就可以修改了。父子进程对nx_prosy的修改不会相互影响。
由于最初的父命名空间需要掌握所有子命名空间的所有pid信息,所有,在各级层次的命名空间的fork中,pid的分配是需要统一协调控制,对于各级子命名空间中的task_struct来说,同一个pid在不同命名空间看到的是不一样的。
同一个进程可以属于多个namespace,多个进程可以使用同一个namespace,
参考链接:
Technorati 标签: namespace 内核