使用Namespace(命名空间),可以让每个进程组具有独立的PID、IPC和网络空间。
可以向clone系统调用的第3个参数flags设置划分命名空间的标志,通过执行clone系统调用可以划分命名空间。
例如,划分PID命名空间后,在新生成的PID命名空间内进程的PID是从1开始的。从新PID为1的进程fork()分叉得到的进程,被封闭到这个新的PID命名空间,与其他PID命名空间分隔开。在新创建的PID命名空间中生成的进程,其PID有可能与存在于原PID命名空间中的进程相同,但由于二者的PID命名空间划分开,就不存在相互影响。
同样,也可以用PID、网络、文件系统的挂载空间、UTS(Universal Time sharing System)为对象进行资源划分。可以在clone系统调用的第3个参数中设置资源划分的种类,如表2-2所示。
表2-2 资源划分
名 称 说 明
CLONE_NEWIPC 划分IPC(进程间通信)命名空间。信号量(semaphore)、共享内存、消息队列等进程间通信用的资源
CLONE_NEWNET 划分网络命名空间。分配网络接口
CLONE_NEWNS 划分挂载的命名空间。与chroot同样分配新的根文件系统
CLONE_NEWPID 划分PID命名空间。分配新的进程ID空间
CLONE_NEWUTS 划分UTS命名空间。分配新的UTS空间
一直对linux内核的namespace感到困惑,今天看了一下代码才知道,原来所谓的namespace其实就是给虚拟化用的,PID namespace其实就是建立一个新的PID空间,这样内部可以使用一套新的PID,而且不会和外部冲突。这也就是说某个进程其实会有两个PID,一个空间一个。
-
#include <errno.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <sys/types.h>
-
#include <unistd.h>
-
#include <sched.h>
-
-
static int fork_child(void *arg)
-
{
-
int a = (int)arg;
-
int i;
-
pid_t pid;
-
-
for (i = 0; i <a; i++) {
-
pid = fork();
-
if (pid <0)
-
return pid;
-
else if (pid)
-
else if (pid == 0) {
-
sleep(3);
-
exit(0);
-
}
-
}
-
return 0;
-
}
-
-
int main(int argc, char *argv[])
-
{
-
int cpid;
-
void *childstack, *stack;
-
int flags;
-
int ret = 0;
-
int stacksize = getpagesize() * 4;
-
-
if (argc != 2) {
-
fprintf(stderr, "Wrong usage.\n");
-
return -1;
-
}
-
-
stack = malloc(stacksize);
-
if (!stack) {
-
perror("malloc");
-
return -1;
-
}
-
-
-
childstack = stack + stacksize;
-
flags = CLONE_NEWPID | CLONE_NEWNS;
-
-
cpid = clone(fork_child, childstack, flags, (void *)atoi(argv[1]));
-
-
if (cpid <0) {
-
perror("clone");
-
ret = -1;
-
goto out;
-
}
-
-
fprintf(stderr, "Parent sleeping 20 seconds\n");
-
sleep(20);
-
ret = 0;
-
-
out:
-
free(stack);
-
return ret;
-
}
我写了段C代码来展示这个问题。
运行结果:
$ sudo ./pid_container 3
Out of the container, my pid is: 7061
cpid: 7062
In the container, my pid is: 1
Parent sleeping 20 seconds
pid of my child is 2
pid of my child is 3
pid of my child is 4
其实被namespace化的不只是PID,还有很多东西,貌似它们合起来被称为container。可以看 include/linux/nsproxy.h:
struct nsproxy {
atomic_t count;
struct uts_namespace *uts_ns;
struct ipc_namespace *ipc_ns;
struct mnt_namespace *mnt_ns;
struct pid_namespace *pid_ns;
struct net *net_ns;
};
虚拟化的东西是越来越让人摸不清头脑了。。。。