Linux namespaces 介绍
namespaces是Linux内核用来隔离内核资源的方式。通过namespaces可以让一些进程只能看到与自己相关的那部分资源。而其它的进程也只能看到与他们自己相关的资源。这两拨进程根本感知不到对方的存在。而它具体的实现细节是通过Linux namespaces来实现的。
总结: Linux namespaces对系统进程进行轻量的虚拟化隔离。
当前Linux内核只支持6中namespaces:
● mnt(mount points, filesystems)
● pid(process)
● net(network stack)
● ipc(System V IPC)
● uts(hostname)
● user(UIDs)
下面是Linux Kernel版本迭代过程中对这6中namespaces的支持情况及对应的flag:
最初打算对Linux内核支持10种namespaces,但是下面的4中没有实现:
● security namespace
● security keys namespaces
● device namespace
● time namespace
接下来先介绍namespace的API,然后在针对Linux内核现在支持的6中namespace分别进行介绍。
代码测试环境:ubuntu20.04.2,kernel版本:5.4.0-182-generic
Namespaces API 介绍
下面3个系统调用API会被用于namespaces:
● clone(): 用于创建新的进程同时创建新的namespaces。并且新的进程会被attach到新的namespace里面。
int clone(int (*fn)(void *), void *child_stack,
int flags, void *arg, ...
/* pid_t *ptid, void *newtls, pid_t *ctid */ );
● 参数child_func传入子进程运行的程序主函数。
● 参数child_stack传入子进程使用的栈空间
● 参数flags表示使用哪些CLONE_*标志位
● 参数args则可用于传入用户参数
ClONE_NEW* flag有20多被包含在include/linux/sched.h头文件中。
● unshare(): 不会创建新的进程,但是会创建新的namesapce并把当前的进程attach到该namespace里面。
int unshare(int flags);
● setns(): 将进程attach到一个已经存在的namespace里面。
int setns(int fd, int nstype);
● 参数fd表示我们要加入的namespace的文件描述符。如:/proc/[pid]/ns下面对应的文件描述符。
● 参数nstype让调用者可以去检查fd指向的namespace类型是否符合我们实际的要求。如果填0表示不检查。
namespace 实践
为了最好的体验还是在 Linux 内核 3.8 以上的系统上进行(这里使用的 Ubuntu 20.04.2, kernel版本:5.4.0-182-generic)。为什么不用 docker for windows 或者 docker for mac 呢?因为这两个其实还是是在 linux 虚拟机上运行 docker 的,docker for windows 需要将 linux 虚拟机装在开启 hyper-v 的 win10 专业版上,而 docker for mac 使用通过 HyperKit 运行 linux 虚拟机。为了方便,使用 c语言代码 来演示循序渐进的达到 Docker 的体验。