Linux PID namespace cgroup namespace container

使用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,一个空间一个。

  1. #include <errno.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <unistd.h>
  6. #include <sched.h>
  7.  
  8. static int fork_child(void *arg)
  9. {
  10.     int a = (int)arg;
  11.     int i;
  12.     pid_t pid;
  13.  
  14.     printf ("In the container, my pid is: %d\n", getpid());
  15.     for (i = 0; i <a; i++) {
  16.         pid = fork();
  17.         if (pid <0)
  18.             return pid;
  19.         else if (pid)
  20.             printf ("pid of my child is %d\n", pid);
  21.         else if (pid == 0) {
  22.             sleep(3);
  23.             exit(0);
  24.         }
  25.     }
  26.     return 0;
  27. }
  28.  
  29. int main(int argc, char *argv[])
  30. {
  31.     int cpid;
  32.     void *childstack, *stack;
  33.     int flags;
  34.     int ret = 0;
  35.     int stacksize = getpagesize() * 4;
  36.  
  37.     if (argc != 2) {
  38.         fprintf(stderr, "Wrong usage.\n");
  39.         return -1;
  40.     }
  41.  
  42.     stack = malloc(stacksize);
  43.     if (!stack) {
  44.         perror("malloc");
  45.         return -1;
  46.     }
  47.  
  48.     printf ("Out of the container, my pid is: %d\n", getpid());
  49.  
  50.     childstack = stack + stacksize;
  51.     flags = CLONE_NEWPID | CLONE_NEWNS;
  52.  
  53.     cpid = clone(fork_child, childstack, flags, (void *)atoi(argv[1]));
  54.     printf ("cpid: %d\n", cpid);
  55.  
  56.     if (cpid <0) {
  57.         perror("clone");
  58.         ret = -1;
  59.         goto out;
  60.     }
  61.  
  62.     fprintf(stderr, "Parent sleeping 20 seconds\n");
  63.     sleep(20);
  64.     ret = 0;
  65.  
  66. out:
  67.     free(stack);
  68.     return ret;
  69. }

 

我写了段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;
};

虚拟化的东西是越来越让人摸不清头脑了。。。。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值