Docker 学习笔记11 容器技术原理 Mount Namespace

网友投稿 294 2022-10-28

Docker 学习笔记11 容器技术原理 Mount Namespace

Docker 学习笔记11 容器技术原理 Mount Namespace

​​一、Mount Namespace作用​​​​二、通过ios文件挂载来演示mount namespace​​

​​1. 安装 mkisofs​​​​2. 演示过程​​​​3. 演示 shared subtree 功能​​

​​三、使用clone 实现 Mount Namespace​​

一、Mount Namespace作用

Mount Namespace为进程提供独立的文件系统视图。 进程的mount namespace中的挂载点信息可以在​​​/proc/[pic]/mounts​​​ ,​​/proc/[pid]/mountinfo​​​ 和 ​​/proc/[pid]/mountstats​​这三个文件中找到。

每个​​mount namespace​​​都有一份自己的挂载点列表。当使用​​clone​​​函数或unshare函数并传入​​CLONE_NEWNS​​​标志创建新的​​mount namespace​​​时,新​​mount namespace​​​中的挂载点其实是从调用者所在的​​mount namespace​​​中拷贝的。但是在新的​​mount namespace​​​创建之后,这两个​​mount namespace​​​及其挂载点基本上没啥关系了,两个​​mount namespace​​是相互隔离的。 (除了shared subtree的情况)。

二、通过ios文件挂载来演示mount namespace

1. 安装 mkisofs

yum install mkisofs -y

2. 演示过程

#--------------------------第一个shell窗口----------------------#先准备两个iso文件,用于后面的mount测试dev@ubuntu:~$ mkdir isodev@ubuntu:~$ cd iso/dev@ubuntu:~/iso$ mkdir -p iso01/subdir01dev@ubuntu:~/iso$ mkdir -p iso02/subdir02dev@ubuntu:~/iso$ mkisofs -o ./001.iso ./iso01dev@ubuntu:~/iso$ mkisofs -o ./002.iso ./iso02dev@ubuntu:~/iso$ ls001.iso 002.iso iso01 iso02#准备目录用于mountdev@ubuntu:~/iso$ sudo mkdir /mnt/iso1 /mnt/iso2#查看当前所在的mount namespacedev@ubuntu:~/iso$ readlink /proc/$$/ns/mntmnt:[4026531840]#mount 001.iso 到 /mnt/iso1/dev@ubuntu:~/iso$ sudo mount ./001.iso /mnt/iso1/mount: /dev/loop1 is write-protected, mounting read-only#mount成功dev@ubuntu:~/iso$ mount |grep /001.iso/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)#创建并进入新的mount和uts namespacedev@ubuntu:~/iso$ sudo unshare --mount --uts /bin/bash#更改hostname并重新加载bashroot@ubuntu:~/iso# hostname container001root@ubuntu:~/iso# exec bashroot@container001:~/iso##查看新的mount namespaceroot@container001:~/iso# readlink /proc/$$/ns/mntmnt:[4026532455]#老namespace里的挂载点的信息已经拷贝到新的namespace里面来了root@container001:~/iso# mount |grep /001.iso/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)#在新namespace中mount 002.isoroot@container001:~/iso# mount ./002.iso /mnt/iso2/mount: /dev/loop0 is write-protected, mounting read-onlyroot@container001:~/iso# mount |grep iso/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)/home/dev/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime)#umount 001.isoroot@container001:~/iso# umount /mnt/iso1root@container001:~/iso# mount |grep iso/home/dev/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime)#/mnt/iso1目录变为空root@container001:~/iso# ls /mnt/iso1root@container001:~/iso##--------------------------第二个shell窗口----------------------#打开新的shell窗口,老namespace中001.iso的挂载信息还在#而在新namespace里面mount的002.iso这里看不到dev@ubuntu:~$ mount |grep iso/home/dev/iso/001.iso on /mnt/iso1 type iso9660 (ro,relatime)#iso1目录里面也有内容dev@ubuntu:~$ ls /mnt/iso1subdir01#说明两个namespace中的mount信息是隔离的

3. 演示 shared subtree 功能

对Shared subtrees而言,mount namespace和bind mount的情况差不多,这里就简单演示一下shared和private两种类型

#--------------------------第一个shell窗口----------------------#准备4个虚拟的disk,并在上面创建ext2文件系统,用于后续的mount测试dev@ubuntu:~/iso$ cd && mkdir disks && cd disksdev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk1.imgdev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk2.imgdev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk3.imgdev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk4.imgdev@ubuntu:~/disks$ mkfs.ext2 ./disk1.imgdev@ubuntu:~/disks$ mkfs.ext2 ./disk2.imgdev@ubuntu:~/disks$ mkfs.ext2 ./disk3.imgdev@ubuntu:~/disks$ mkfs.ext2 ./disk4.img#准备两个目录用于挂载上面创建的diskdev@ubuntu:~/disks$ mkdir disk1 disk2dev@ubuntu:~/disks$ lsdisk1 disk1.img disk2 disk2.img disk3.img disk4.img#显式的分别以shared和private方式挂载disk1和disk2dev@ubuntu:~/disks$ sudo mount --make-shared ./disk1.img ./disk1dev@ubuntu:~/disks$ sudo mount --make-private ./disk2.img ./disk2dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105173 24 7:2 / /home/dev/disks/disk2 rw,relatime#查看mount namespace编号dev@ubuntu:~/disks$ readlink /proc/$$/ns/mntmnt:[4026531840]#--------------------------第二个shell窗口----------------------#重新打开一个新的shell窗口dev@ubuntu:~$ cd ./disks#创建新的mount namespace#默认情况下,unshare会将新namespace里面的所有挂载点的类型设置成private,#所以这里用到了参数--propagation unchanged,#让新namespace里的挂载点的类型和老namespace里保持一致。#--propagation参数还支持private|shared|slave类型,#和mount命令的那些--make-private参数一样,#他们的背后都是通过调用mount(...)函数传入不同的参数实现的dev@ubuntu:~/disks$ sudo unshare --mount --uts --propagation unchanged /bin/bashroot@ubuntu:~/disks# hostname container001root@ubuntu:~/disks# exec bashroot@container001:~/disks# #确认已经是在新的mount namespace里面了root@container001:~/disks# readlink /proc/$$/ns/mntmnt:[4026532463]#由于前面指定了--propagation unchanged,#所以新namespace里面的/home/dev/disks/disk1也是shared,#且和老namespace里面的/home/dev/disks/disk1属于同一个peer group 105#因为在不同的namespace里面,所以这里挂载点的ID和原来namespace里的不一样了root@container001:~/disks# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'221 177 7:1 / /home/dev/disks/disk1 rw,relatime shared:105222 177 7:2 / /home/dev/disks/disk2 rw,relatime#分别在disk1和disk2目录下创建disk3和disk4,然后挂载disk3,disk4到这两个目录root@container001:~/disks# mkdir ./disk1/disk3 ./disk2/disk4root@container001:~/disks# mount ./disk3.img ./disk1/disk3/root@container001:~/disks# mount ./disk4.img ./disk2/disk4/root@container001:~/disks# cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'221 177 7:1 / /home/dev/disks/disk1 rw,relatime shared:105222 177 7:2 / /home/dev/disks/disk2 rw,relatime223 221 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107227 222 7:4 / /home/dev/disks/disk2/disk4 rw,relatime#--------------------------第一个shell窗口----------------------#回到第一个shell窗口#可以看出由于/home/dev/disks/disk1是shared,且两个namespace里的这个挂载点都属于peer group 105,#所以在新namespace里面挂载的disk3,在老的namespace里面也看的到#但是看不到disk4的挂载信息,那是因为/home/dev/disks/disk2是private的dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105173 24 7:2 / /home/dev/disks/disk2 rw,relatime224 164 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107#我们可以随时修改挂载点的propagation type#这里我们通过mount命令将disk3改成了private类型dev@ubuntu:~/disks$ sudo mount --make-private /home/dev/disks/disk1/disk3dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk3| sed 's/ - .*//'224 164 7:3 / /home/dev/disks/disk1/disk3 rw,relatime#--------------------------第二个shell窗口----------------------#回到第二个shell窗口,disk3的propagation type还是shared,#表明在老的namespace里面对propagation type的修改不会影响新namespace里面的挂载点root@container001:~/disks# cat /proc/self/mountinfo |grep disk3| sed 's/ - .*//'223 221 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107

三、使用clone 实现 Mount Namespace

代码:

#define _GNU_SOURCE#include #include #include #include #include #include /* 定义一个给 clone 用的栈,栈大小1M */#define STACK_SIZE (1024 * 1024)static char container_stack[STACK_SIZE];char* const container_args[] = { "/bin/bash", NULL};int container_main(void* arg){ printf("Container [%5d] - inside the container!\n", getpid()); sethostname("container",10); /* 重新mount proc文件系统到 /proc下 */ system("mount -t proc proc /proc"); execv(container_args[0], container_args); printf("Something's wrong!\n"); return 1;}int main(){ printf("Parent [%5d] - start a container!\n", getpid()); /* 启用Mount Namespace - 增加CLONE_NEWNS参数 */ int container_pid = clone(container_main, container_stack+STACK_SIZE, CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWNS | SIGCHLD, NULL); waitpid(container_pid, NULL, 0); printf("Parent - container stopped!\n"); return 0;}

运行效果:

[root@localhost c4]# ./a.out Parent [23983] - start a container!Container [ 1] - inside the container![root@container c4]# ps -elfF S UID PID PPID C PRI NI ADDR SZ WCHAN STIME TTY TIME CMD4 S root 1 0 0 80 0 - 28886 wait 15:37 pts/1 00:00:00 /bin/bash0 R root 16 1 0 80 0 - 35420 - 15:37 pts/1 00:00:00 ps -elf[root@container c4]# ls /proc1 buddyinfo consoles diskstats fb iomem kcore kpagecount mdstat mounts partitions slabinfo sys timer_stats vmallocinfo17 bus cpuinfo dma filesystems ioports keys kpageflags meminfo mtrr sched_debug softirqs sysrq-trigger tty vmstatacpi cgroups crypto driver fs irq key-users loadavg misc net scsi stat sysvipc uptime zoneinfoasound cmdline devices execdomains interrupts kallsyms kmsg locks modules pagetypeinfo self swaps timer_list version[root@container c4]#

可以看到只有两个进程,而且pid=1是/bin/bash本身进程。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:多路读写SDRAM接口设计
下一篇:基于FPGA的PCI总线接口设计
相关文章

 发表评论

暂时没有评论,来抢沙发吧~