百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Docker学习9 容器原理 Mount Namespace每天几分钟进步一点点

liebian365 2024-11-09 13:45 31 浏览 0 评论



一、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 iso
dev@ubuntu:~$ cd iso/
dev@ubuntu:~/iso$ mkdir -p iso01/subdir01
dev@ubuntu:~/iso$ mkdir -p iso02/subdir02
dev@ubuntu:~/iso$ mkisofs -o ./001.iso ./iso01
dev@ubuntu:~/iso$ mkisofs -o ./002.iso ./iso02
dev@ubuntu:~/iso$ ls
001.iso  002.iso  iso01  iso02
#准备目录用于mount
dev@ubuntu:~/iso$ sudo mkdir /mnt/iso1 /mnt/iso2

#查看当前所在的mount namespace
dev@ubuntu:~/iso$ readlink /proc/$/ns/mnt
mnt:[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 namespace
dev@ubuntu:~/iso$ sudo unshare --mount --uts /bin/bash
#更改hostname并重新加载bash
root@ubuntu:~/iso# hostname container001
root@ubuntu:~/iso# exec bash
root@container001:~/iso#

#查看新的mount namespace
root@container001:~/iso# readlink /proc/$/ns/mnt
mnt:[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.iso
root@container001:~/iso# mount ./002.iso /mnt/iso2/
mount: /dev/loop0 is write-protected, mounting read-only
root@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.iso
root@container001:~/iso# umount /mnt/iso1
root@container001:~/iso# mount |grep iso
/home/dev/iso/002.iso on /mnt/iso2 type iso9660 (ro,relatime)

#/mnt/iso1目录变为空
root@container001:~/iso# ls /mnt/iso1
root@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/iso1
subdir01
#说明两个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 disks
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk1.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk2.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk3.img
dev@ubuntu:~/disks$ dd if=/dev/zero bs=1M count=32 of=./disk4.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk1.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk2.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk3.img
dev@ubuntu:~/disks$ mkfs.ext2 ./disk4.img
#准备两个目录用于挂载上面创建的disk
dev@ubuntu:~/disks$ mkdir disk1 disk2
dev@ubuntu:~/disks$ ls
disk1  disk1.img  disk2  disk2.img  disk3.img  disk4.img


#显式的分别以shared和private方式挂载disk1和disk2
dev@ubuntu:~/disks$ sudo mount --make-shared ./disk1.img ./disk1
dev@ubuntu:~/disks$ sudo mount --make-private ./disk2.img ./disk2
dev@ubuntu:~/disks$ cat /proc/self/mountinfo |grep disk| sed 's/ - .*//'
164 24 7:1 / /home/dev/disks/disk1 rw,relatime shared:105
173 24 7:2 / /home/dev/disks/disk2 rw,relatime

#查看mount namespace编号
dev@ubuntu:~/disks$ readlink /proc/$/ns/mnt
mnt:[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/bash
root@ubuntu:~/disks# hostname container001
root@ubuntu:~/disks# exec bash
root@container001:~/disks# 

#确认已经是在新的mount namespace里面了
root@container001:~/disks# readlink /proc/$/ns/mnt
mnt:[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:105
222 177 7:2 / /home/dev/disks/disk2 rw,relatime

#分别在disk1和disk2目录下创建disk3和disk4,然后挂载disk3,disk4到这两个目录
root@container001:~/disks# mkdir ./disk1/disk3 ./disk2/disk4
root@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:105
222 177 7:2 / /home/dev/disks/disk2 rw,relatime
223 221 7:3 / /home/dev/disks/disk1/disk3 rw,relatime shared:107
227 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:105
173 24 7:2 / /home/dev/disks/disk2 rw,relatime
224 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/disk3
dev@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 <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <sched.h>
#include <signal.h>
#include <unistd.h>

/* 定义一个给 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 -elf
F S UID        PID  PPID  C PRI  NI ADDR SZ WCHAN  STIME TTY          TIME CMD
4 S root         1     0  0  80   0 - 28886 wait   15:37 pts/1    00:00:00 /bin/bash
0 R root        16     1  0  80   0 - 35420 -      15:37 pts/1    00:00:00 ps -elf
[root@container c4]# ls /proc
1       buddyinfo  consoles  diskstats    fb           iomem     kcore      kpagecount  mdstat   mounts        partitions   slabinfo  sys            timer_stats  vmallocinfo
17      bus        cpuinfo   dma          filesystems  ioports   keys       kpageflags  meminfo  mtrr          sched_debug  softirqs  sysrq-trigger  tty          vmstat
acpi    cgroups    crypto    driver       fs           irq       key-users  loadavg     misc     net           scsi         stat      sysvipc        uptime       zoneinfo
asound  cmdline    devices   execdomains  interrupts   kallsyms  kmsg       locks       modules  pagetypeinfo  self         swaps     timer_list     version
[root@container c4]# 

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

运行top命令:

在通过CLONE_NEWNS创建mount namespace后,父进程会把自己的文件结构复制给子进程中。而子进程中新的namespace中的所有mount操作都只影响自身的文件系统,而不对外界产生任何影响。这样可以做到比较严格地隔离。

相关推荐

深度解密epoll 如何工作的?(epoll基本处理流程)

epoll...

大乐透第19082期:头奖开出7注1000万分落六地 奖池41亿元

2019年7月17日晚开奖的体彩超级大乐透第19082期开奖号码为:前区06、18、20、21、31,后区03、04。本期大乐透前区号码五区比为1:0:3:0:1,二区和四区号码没有给出。当期前区和值...

【开奖】4月27日周六:福彩、体彩(2021年4月27日体彩开奖结果)

4月27日开奖福彩3D第2019110期:61222选5第2019110期:0812202122排列3第19110期:303排列5第19110期:30305大乐透第19047期:0304...

“红狒狒”落户哈尔滨铁路局(哈尔滨铁路红肠)

这几天,“红人”“红狒狒”在牡丹江机务段可引起了不小的轰动,众粉丝争相与其拍照留念,在该段人气爆棚!“红狒狒”到底何许人也?“红狒狒”,中文名:和谐3D型电力机车;绰号:红狒狒、番茄;制造商:大连机...

2D、3D、2.5D,做游戏还是搞噱头?玩家都晕了

前言游戏类型就像某种潮流,一种流行罢,另一种接棒成为主流。前两年的新作大多以“开放世界”为标签,在追求纯沙盒的过程中打造出一些细致的分类,比如说“类GTA沙盒”。诚然,纯碎的沙盒游戏并不多见,业内只有...

《战神4》PC版宣传片发布 GTX 1070即可60帧畅玩

在今年10月的时候索尼PlayStation官方正式宣布圣莫尼卡2018年的《战神4》将于2022年1月14日推出PC版本,官方在今天公布了一段PC版宣传片,并且公开了游戏的配置需求。下面让我们一起来...

男星深情好丈夫形象崩塌,半夜搂美女坐大腿,举止亲密

近日,于晓光被拍到深夜在酒吧玩,结束后与一名女子一起上车离开。上车后,女子直接坐在了他腿上,他也顺势搂着美女,美女满脸笑容地坐在他腿上玩手机离开。可能有人会好奇,于晓光是谁呢?于晓光是韩国艺人秋瓷炫的...

d3d12dll丢失怎么修复?d3d12dll加载失败怎么解决?

  d3d12.dll丢失怎么修复?d3d12.dll加载失败怎么解决?很多朋友想要运行游戏的时候都会遇到这个问题,这种情况该怎么办呢?今天系统之家小编给朋友们讲讲具体的解决方法,操作其实还蛮简单的。...

许多玩家反馈《生化4RE》PC一直崩溃 无法进入游戏

今日(3月24日),卡普空《生化危机4:重制版》正式发售,然而有部分PC玩家遇到了游戏崩溃等问题。很多玩家在贴吧发帖称游戏遇到了严重的崩溃问题,且经常反复,报错代码普遍为FatalD3Derror...

微软正式推出适用于WSL Linux的D3D12 GPU视频加速技术

今天,微软正式向WindowsSubsystemforLinux(WSL)用户发布了Direct3D12GPU视频加速支持。在微软通过WSL允许在Linux下使用Open...

《怪物猎人:崛起》曙光系统报错“Fatal d3d error”的解决办法

《怪物猎人:崛起》曙光系统报错“Fatald3derror”的解决办法不少小伙伴反应《怪物猎人:崛起》DLC曙光预载以后打不开游戏,出现了Fatald3derror类似的错误代码,这类问题的解...

Mac+双屏,前端程序员的专业配置 - Loctek 乐歌 D3D 双屏电脑显示器支架

做FE也有一段日子了,电脑屏幕每天在设计稿、浏览器、IDE、即时通讯工具、Terminal、邮箱之间切换。虽然mac的工作区带来了很多灵活,但是依然略显不足。于是入手支架,把公司配的电脑和显示器发挥起...

RPC 的原理和简单使用(rpc详解)

RPC的概念RPC,RemoteProcedureCall,翻译成中文就是远程过程调用,是一种进程间通信方式。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数。在调用的...

大厂开源的golang微服务rpc框架 — kitex

提前rpc估计所有的开发同学都知道,不知道的也无所谓,毕竟我也好几年没用了,今天带大家在复习一下。RPC(RemoteProcedureCall):远程过程调用,...

干货!一文掌握Protobuf所有语言所有用法,快收藏

说实话,Protobuf这个库,让人相见时难别亦难,东风无力百花残,每次等到要用它的时候,总感觉还没有完全掌握它的用法,而实际上等去百度或者谷歌的时候,教程都是多么的凌乱不堪。学会它,最直接关系到的,...

取消回复欢迎 发表评论: