1. 什么是命名空间
Linux中的命名空间(namespaces)是一种轻量级的虚拟化技术(ps:docker就是依赖这个原理实现的)
,让进程看起来像是在自己的独立系统中运行,也就是说进程只能看到相同命名空间内的进程和资源,而看不到其他命名空间的资源。
Linux的命名空间包括以下几种类型:
-
Mount namespaces
:在不同的Mount namespaces中,进程可以看到不同的文件系统层次结构。
-
PID namespaces
:在不同的PID namespaces中,进程有自己的PID空间,允许在每个命名空间中都有一个PID为1的进程。ps:PID=1的进程通常为init进程
-
Network namespaces
:提供独立的网络设备、IP地址、路由表等。
-
Interprocess Communication (IPC) namespaces
:隔离对IPC的访问,例如消息队列、信号量等。
-
UTS namespaces
:隔离主机名和域名。
-
User namespaces
:隔离用户和用户组ID,允许在用户空间转换用户ID和组ID。
一个Linux进程在一个或多个命名空间中执行,通过这种技术,可以实现容器(如Docker等)的隔离
,让容器中的进程只能看到容器内的资源,而看不到机器上的其他资源,这样就提供了一种安全和隔离的运行环境。
2. 进程如何跟命名空间关联起来的
在 Linux 中,刚创建的进程会继承创建它的进程的所有命名空间。但是,你可以用一些系统调用来改变一个已存在进程的命名空间关联,或者在创建新进程时指定其命名空间。
创建新命名空间的主要方法是用 clone()
系统调用。clone()
是 fork()
和 exec()
的更通用版本,它在创建新进程的同时还支持更多的定制选项。其中有几个选项可以用来创建新的命名空间,如 CLONE_NEWPID
、CLONE_NEWNET
、CLONE_NEWUSER
等。
pid_t pid = clone(child_func, child_stack, CLONE_NEWPID | CLONE_NEWNET | SIGCHLD, NULL);
在上面的代码中,clone()
创建了一个新的进程,并且这个新进程拥有自己的 PID 和网络命名空间。
如果你要改变一个已存在进程的命名空间,你可以使用 setns()
系统调用。每个命名空间在 /proc 文件系统中都有一个对应的文件描述符。你可以打开一个命名空间的文件描述符,然后用 setns()
把进程关联到那个命名空间。
int fd = open("/proc/<PID>/ns/net", O_RDONLY); // 打开另一个命名空间
setns(fd, CLONE_NEWNET); // 把当前进程关联到另一个网络命名空间
请注意,要修改进程的命名空间需要适当的权限。一般来说,你需要 root 权限才能执行这些操作。
3. linux中进程如何定位自己的命名空间
每个进程都可以通过查阅 /proc
文件系统下特定的信息,来找到其所在的各种命名空间。在 /proc
文件系统中,每个进程都有一个唯一数字ID对应的目录(即进程ID),里面包含了该进程的各种信息。其中,ns
目录包含了该进程所在命名空间的链接。
比如说,你想查询进程ID为1234的进程所在的各种命名空间,你可以查看 /proc/1234/ns
目录下的内容:
ls -l /proc/1234/ns
输出例子:
total 0
lrwxrwxrwx 1 root root 0 Apr 17 12:00 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Apr 17 12:00 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Apr 17 12:00 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Apr 17 12:00 net -> net:[4026531957]</