1 设计目标
对特定的系统全局资源进行封装,提供一个抽象层,使不同名字空间内的进程认为自己拥有这些全局资源的一个隔离的实例。
2 目前实现的Namespace
下文各标题的括号内为设置相关名字空间时需传入的标识。
2.1 Mount Namespaces(CLONE_NEWNS)
该名字空间为一组进程提供隔离的文件系统挂载点。位于不同Mount Namespace的进程可以看到不同的文件系统的层级。当隔离Mount Namespace之后,通过mount()和umount()对文件系统的挂载点的设置不会影响其他名字空间的进程,这使得不同的进程可以拥有不同的文件系统挂载层级。配合chroot()之类的根文件系统切换的系统调用,可以使不同的进程看到不同的根文件系统。
2.2 UTS Namespaces(CLONE_NEWUTS)
UTS是“Unix Time-Sharing”的缩写,但该名字空间主要用于为主机名(hostname)和域名(domain name)提供隔离机制。意即通过设置该名字空间之后,同属于该名字空间的所有进程共享同样的主机名和域名,而系统中其他名字空间的进程可以拥有不同的主机名和域名。
2.3 IPC Namespaces(CLONE_NEWIPC)
该名字空间主要为System V IPC和POSIX Message Queue之类的IPC对象提供隔离。这些IPC的共同点是它们都是在系统中通过某种key的形式表示,而不是利用路径名来表示。
2.4 PID Namespaces(CLONE_NEWPID)
该名字空间用于隔离PID,使得不同的名字空间可以拥有不同的PID。对于隔离PID名字空间后启动的第一进程,其PID为1,扮演着Init进程的角色。从该进程启动的其他进程都属于该名字空间,当这些进程变成孤儿进程时,默认由该名字空间内的PID为1的进程“领养”。由于Init进程的特殊性,如果该名字空间内的第一个进程没有设置任何信号句柄处理函数,则该名字空间内的其他进程均无法向PID为1的进程发送任何信号。
2.5 Network Namespaces(CLONE_NEWNET)
该名字空间用于隔离网络相关的资源,包括IP地址、端口号、路由表、IPv4和IPv6协议栈等。利用该名字空间可以使某个进程内部使用固定的端口号,而外部则使用其他的端口号。此外,可利用与管道类似的机制使不同Network名字空间的进程进行通信。如果有超过两个Network名字空间的进程需要利用网络进行通信,则需要创建虚拟网卡和虚拟交换机等,并配置的相应的路由信息等,才能保证正常的通信。
2.6 User Namespaces(CLONE_NEWUSER)
其他的名字空间均属于某一个User名字空间,意即每个User名字空间拥有其他类型的名字空间。该名字空间用于提供与用户标识等安全相关的资源隔离,如UID和GID等。这样,内部User名字空间的进程可以具有UID=0的用户,具备root的权限,而在外部User名字空间的UID则保持为原来的值不变,不会获得特殊权限。
2.7 CGroup Namespace(CLONE_NEWCGROUP)
该名字空间提供了对CGroup的隔离。隔离CGroup名字空间之后,进程可以修改该名字空间内的CGroup而不影响其他名字空间的进程,并且位于隔离的CGroup名字空间的进程其CGroup绝对路径是从一个新的CGroup开始的,这为后续创建新的CGroup提供了更一致的路径表示。
3 相关系统调用
3.1 clone()
函数原型:
int clone(int (*fn)(void *), void *stack, int flags, void *arg, ...
/* pid_t *parent_tid, void *tls, pid_t *child_tid */ );
可以在利用clone创建新进程的时候传入相关的名字空间标识,使得新的进程在设置的新的名字空间内运行。
3.2 unshare()
函数原型:
int unshare(int flags);
该系统调用可以更改当前进程的名字空间。注意,PID名字空间隔离后,并不会改变当前进程的pid,而是会影响之后通过fork()、clone()等创建子进程时子进程的pid。
3.3 setns()
函数原型:
int setns(int fd, int nstype);
该系统调用可以将当前进程的名字空间修改为指定的文件描述符表示的名字空间。对于PID名字空间的注意事项同3.2.