namespace资源隔离
6项隔离
image.png
API
clone()
使用clone。来创建一个独立namespace的进程,是最常见的做法,也是Docker使用namespace最基本的方法,它的调用方式如下.
int clone(int (*child_func)(void *), void *child_stack, int flags, void *arg);
child_func传入子进程运行的程序主函数。
childstack传入子进程使用的栈空间。
flags表示使用哪些CLONE_标志位,与namespace相关的主要包括CLONE_NEWIPC、
CLONE_NEWNS、CLONE_NEWNET、CLONE_NEWPID、CLONE_NEWUSER和CLONE_NEWUTS。
args应可用于传入用户参数。
setns()
通过setns()系统调用,进程从原先的namespace加入到某个已经存在的namespace,使用方法如下。通常为了不影响进程的调用者,也为了使新加入的pid namespace生效, 会在setns()函数执行后使用clone。创建子进程继续执行命令,让原先的进程结束运行。
int setns(int fd, int nstype);
docker exec就使用了此方法
- 参数fd表示要加入namespace的文件描述符。它是一个指向/ptoc/[pid]/ns目
录的文件描述符,可以通过直接打开该目录下的链接或者打开一个挂裁了该目录下链接的文件得到。 - 参数nstype让调用者可以检査fd指向的namespace类型是否符合实际要求。该参数为0表示
不检査。
为了把新加入的namespace利用起来,需要引入execvp()系列函数,该函数可以执行用户询
令,最常用的就是调用/bin/bash并接受参数,运行起一个shell,用法如下。
fd = open(argv[1], O_RDONLY);
setns(fd, 0);
execvp(argv[2], &argv[2]);
./setns-test ~/uts /bin/bash // 在此之前需要将/ptoc/[pid]/ns 挂载到uts
unshare()
调用unshare()的主要作用就是,不启动新进程就可以起到隔离的效果,相当于跳出原先的
namespace进行操作。这样,就可以在原进程进行一些需要隔离的操作。Linux中自带的unshare命令,就是通过unshare()系统调用实现的。
查看/proc/[pid]/ns文件
从3.8版本的内核开始,用户就可以在/proc/[pid]/ns文件下看到指向不同namespace号的文件,效果如下所示,形如[4026531839]者即为namespace号。
image.png
fork()
当程序调用fork函数时,系统会创建新的进程,为其分配资源,例如存储数据和代码的空间,然后把原来进程的所有值都复制到新进程中,只有少量数值与原来的进程值不同,相当于复制了本身。那么程序的后续代码逻辑要如何区分自己是新进程还是父进程呢?
fork的神奇之处在于它仅仅被调用一次,却能够返回两次(父进程与子进程各返回一次),通过返回值的不同就可以区分父进程与子进程。它可能有以下3种不同的返回值:
- 在父进程中,fork返回新创建子进程的进程ID;
- 在子进程中,fork返回0;
- 如果出现错误,fork返回一个负值。
image.png