linux(centos8):使用namespace做资源隔离
一,namespace是什么?
namespace 是 Linux 内核用来隔离内核资源的方式。
它是对全局系统资源的封装隔离,
处于不同 namespace 的进程拥有独立的全局系统资源,
改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程,
对其他 namespace 中的进程没有影响
每个namespace下的资源对于其他namespace下的资源是透明的,不可见的。
从操作系统角度看,可以出现多个相同pid的进程,
由于它们属于不同的namespace,所以进程之间并不冲突。
从用户角度看,只能看到属于用户自己namespace下的资源,
例如:ps命令只能列出自己namespace下的进程。
说明:刘宏缔的架构森林是一个专注架构的博客,
网站:https://blog.imgtouch.com
本文: https://blog.imgtouch.com/index.php/2023/05/22/centos8linux-shi-yong-namespace-zuo-zi-yuan-ge-li/
对应的源码可以访问这里获取: https://github.com/liuhongdi/
说明:作者:刘宏缔 邮箱: 371125307@qq.com
二,namespace的用途?
当前linux内核中提供了7类namespace,分别用于:
Cgroup :Cgroup 根目录
IPC :System V IPC/POSIX 消息队列
Network :网络设备/协议栈/端口
Mount :挂载点
PID :进程ID
User :用户和group ID
UTS :Hostname和NIS域名
三,查看一个进程所属的namespace
1,得到一个nginx进程的id
[root@blog ~]# ps auxfww | grep nginx: root 491 0.0 0.0 71028 3368 ? Ss May18 0:00 nginx: master process /usr/local/openresty/nginx/sbin/nginx nginx 492 0.0 0.0 102496 7036 ? S May18 0:00 \_ nginx: worker process nginx 493 0.0 0.0 102764 7496 ? S May18 0:00 \_ nginx: worker process nginx 494 0.0 0.0 102496 5856 ? S May18 0:00 \_ nginx: worker process …
我们选择492这个进程
2,查看492这个进程的namespace
[root@blog ~]# ls /proc/492/ns/ cgroup ipc mnt net pid pid_for_children user uts
3,这些namespace文件的类型是符号链接
[root@blog ns]# ll /proc/492/ns/ total 0 lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 cgroup -> 'cgroup:[4026531835]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 ipc -> 'ipc:[4026531839]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 mnt -> 'mnt:[4026532277]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 net -> 'net:[4026531992]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 pid -> 'pid:[4026531836]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 pid_for_children -> 'pid:[4026531836]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 user -> 'user:[4026531837]' lrwxrwxrwx 1 nginx nginx 0 Jun 15 13:32 uts -> 'uts:[4026531838]’
链接文件的内容的格式为 xxx:[inode number]。
xxx 是 namespace 的类型,
inode number 用来标识一个 namespace,
四,查看一个进程的mnt namespace信息
1,mnt namespace的挂载点信息,记录在下面的3个文件中
[root@blog ns]# ll /proc/492/mount* -r--r--r-- 1 nginx nginx 0 Jun 13 23:23 /proc/492/mountinfo -r--r--r-- 1 nginx nginx 0 Jun 13 23:23 /proc/492/mounts -r-------- 1 nginx nginx 0 Jun 13 23:23 /proc/492/mountstats
mnt namespace的作用:隔离mount point,
每个mnt namespace内的文件结构可以单独进行修改,互不影响
2,我们做一个试验验证mnt namespace:
先创建两个目录,下面各创建一个文件:
[root@localhost ~]# mkdir /root/hosta [root@localhost ~]# touch /root/hosta/a.txt [root@localhost ~]# mkdir /root/hostb [root@localhost ~]# touch /root/hostb/b.txt
查看当前的mnt目录:
[root@localhost ~]# ls /mnt hgfs
新开启两个终端:
在终端a中进行如下操作:
创建新的mount namespace和uts namespace,并运行bash
[root@localhost ~]# unshare --mount --uts bash
修改主机名为hosta
[root@localhost ~]# hostname hosta && exec bash
查看当前进程中mnt和uts两个namespace的inode number
#$$:当前的进程id
[root@hosta ~]# readlink /proc/$$/ns/{mnt,uts} mnt:[4026532774] uts:[4026532775]
挂载hosta目录到mnt下
[root@hosta ~]# mount --bind hosta/ /mnt/ [root@hosta ~]# ls /mnt a.txt
3,回到最早的localhost终端中查看:
[root@localhost ~]# ls /mnt hgfs
/mnt目录下的内容没有变,说明localhost终端与 hosta终端的mount namespace是成功隔离的
在终端b中进行以下操作:
创建新的mount namespace和uts namespace,并运行bash
[root@localhost ~]# unshare --mount --uts bash
修改主机名为hostb
[root@localhost ~]# hostname hostb && exec bash
查看当前进程中mnt和uts两个namespace的inode number
#$$:当前的进程id
[root@hostb ~]# readlink /proc/$$/ns/{mnt,uts} mnt:[4026532706] uts:[4026532707]
挂载hostb目录到mnt下
[root@hostb ~]# mount --bind hostb/ /mnt/ [root@hostb ~]# ls /mnt b.txt
五,测试pid namespace
#—fork:以unshare的子进程来启动bash
[root@localhost ~]# unshare --pid --uts --mount --fork bash
修改hostname,作为标识
[root@localhost ~]# hostname hosta && exec bash [root@hosta ~]# echo $$ 1
当前的进程id是1
#-p:显示pid
#-l: 显示长的行(不按COLUMNS这个环境变量去截取宽度)
[root@hosta ~]# pstree -pl systemd(1)─┬─ModemManager(871)─┬─{ModemManager}(911) │ └─{ModemManager}(924) ├─NetworkManager(867)─┬─dhclient(993) │ ├─{NetworkManager}(915) │ └─{NetworkManager}(925) …
用pstree可以看到:pid为1的进程是systemd
这是因为这里的proc是unshare给带来的mount namespace的/proc
包括查看ns下的inode number也是如此,
[root@hosta ~]# readlink /proc/$$/ns/{pid,uts,mnt} pid:[4026531836] uts:[4026531838] mnt:[4026531840]
需要重新挂载/proc
[root@hosta liuhongdi]# mount --types proc proc /proc/ [root@hosta liuhongdi]# pstree -pl bash(1)───pstree(70)
说明:如果用unshare启动bash时,加 --mount-proc 参数,则不需要重新挂载/proc
再次查看ns下的inode number,也可以正确显示了
[root@hosta liuhongdi]# readlink /proc/$$/ns/{pid,uts,mnt} pid:[4026532779] uts:[4026532778] mnt:[4026532777]
六,查看linux的版本:
[root@node1 ~]# more /etc/redhat-release CentOS Linux release 8.1.1911 (Core) [root@node1 ~]# uname -r 4.18.0-147.el8.x86_64