aufs挂载例程

  由于设备需要能回复出产设置功能,以前都是将最原始的文件都备份一份, 但是目前存在一个问题:系统升级后只是修改了一小部分文件,很多内容没有修改,这样就导致备份的大多数内容其实在浪费空间;那能不能和fork 那样做到cow呢?也就是升级的时候你要修改此文件,我才去备份!这样节约存储空间。so可以参考docker的aufs文件系统来设计自己的系统数据盘

mount -n -t aufs -o br:/fp/modified/root=rw :/fp/update/root=ro+wh :/fp/orig/root=rr,noatime unionfs /union_root

   当需要修改一个文件,而该文件位于低层branch时,顶层branch会直接复制低层branch的文件至顶层再进行修改,而低层的文件不变,这种方式即是CoW技术(写复制),AUFS默认支持Cow技术。

  当删除一个低层branch文件时,只是在顶层branch对该文件进行重命名并隐藏,实际并未删除文件,只是不可见,这种方式即AUFS的whiteout(写隐藏)。

  写时复制(copy-on-write,常被简写为 CoW),也叫隐式共享,是一种提高资源使用效率的资源管理技术。它的思想是:如果一个资源是重复的,在没有对资源做出修改前,并不需要立即复制出一个新的资源实例,这个资源被不同的所有者共享使用。当任何一个所有者要对该资源做出修改时,复制出一个新的资源实例给该所有者进行修改,修改后的资源成为其所有者的私有资源。通过这种资源共享的方式,可以显著地减少复制相同资源带来的消耗,但是这样做也会在进行资源的修改时增加一部分开销

  aufs文件系统一旦挂载,只能对挂载联合文件系统的目录进行操作,不能对其他用于合并的目录进行操作。节省空间:AUFS 的 CoW 特性能够允许在多个容器之间共享分层,从而减少物理空间占用。

  • 查找文件:AUFS 的找性能在层数非常多时会出现下降,层数越多,查找性能越低。
  • 性能:AUFS 的 CoW 特性在写入大型文件时第一次会出现延迟。
$ tree .
├── dir1
│ ├── a
│ └── b
├── dir2
│ ├── b
│ └── c
└── mnt

 

 mount -t aufs -o dirs=./dir1:./dir2 none ./mnt

$echo hello > ./mnt/b
$ cat ./dir1/b
hello
$ cat ./dir2/b

  我们向dir1和dir2都同时拥有的文件b中写入了一个test,上层目录dir1中的b的内容被修改为了test,而下层目录dir2中的b 依然是空的。所以修改unionFS中的文件,只会修改最上层的文件,这就是aufs的一些简单的功能

  aufs联合文件系统在用在制作系统盘时的主要作用有2个,系统升级和系统恢复。

系统升级主要是更新系统。系统恢复主要是当系统不正常或误删系统文件的时候,可以将系统恢复正常和恢复rootfs误删的系统文件。

系统升级:

当我们需要进行升级的时候,通过将升级的系统文件解压到update层和modified层来实现升级,解压到modified层是为了立即生效,解压到update层是为了备份升级内容。

系统恢复:

恢复到打了升级包的状态:

场景:系统出问题,需要恢复系统,但是想保留之前打的所有升级包内容,包括修复的漏洞,解决的bug等。

方案:通过删除aufs文件系统中modified层中root和nsfocus目录中的所有内容后,重启,则恢复到了升级后的版本

恢复出厂设置:

场景:系统出问题,需要恢复系统,直接恢复到出厂设置。

方案:通过删除aufs文件系统中modified层和update层中root和nsfocus目录中的所有内容后,重启,则恢复到了出厂设置。

mount -n -t aufs -o \
br:/fp/modified/root=rw\
:/fp/update/root=ro+wh\
:/fp/orig/root=rr,noatime unionfs /union_root
/bin/mount -n -t aufs -o remount,udba=notify,noatime,noxino unionfs /union_root

mount -n -t aufs -o \
br:/fp/modified/fpwork=rw\
:/fp/update/fpwork=ro+wh\
:/fpwork=rr,noatime unionfs /union_root/fproot/fpwork
/bin/mount -n -t aufs -o remount,udba=notify,noatime,noxino unionfs /union_root/fproot/fpwork
View Code

 

  目前存在一个问题:由于orig层使用的是rr 权限挂载,所有修改文件权限就会触发COW; 就会将问价copy 一份到modify中去

 

  Ubuntu 系统默认已经安装了 aufs,对应的安装包是 aufs-tools。下面我们就做一个简单的试验,看看 aufs 具体的样子。

工作目录可以随便选择,后面的操作都是在这个目录进行的。首先创建三个子目录:

  • base 作为底层的目录
  • top 作为上层的目录
  • mnt: aufs 使用的挂载点,会把上面两个目录挂载到这里

然后创建几个文件,如下:

➜  tree                     
.
├── base
│   ├── common.txt
│   └── hello.txt
├── mnt
└── top
    ├── common.txt
    └── foo.txt

 

接下来使用 aufs,把 base 和 top 一起 mount 到 ./mnt 目录:

sudo mount -t aufs -o br=./top:./base none ./mnt

 

在 aufs 中,base/ 和 top/ 被称为 branch,它们就是源目录。

这个 mount 命令的参数意义是这样的:

  • -t aufs:mount 的文件类型,使用的是 aufs
  • -o:传递个 aufs 的选项,每个文件类型的选项不同
  • br:表示 branch,也就是 aufs 需要的的各个目录
  • none:这个本来是设备的名字,但是我们并没有用到任何设备,只会用到文件夹,因此这里为 none
  • ./mnt:挂载点,也就是内容最终出现的目录

默认情况下,-o 后面的第一个目录是以可读写模式挂载的,剩下的目录都是只读模式(和 docker 容器模型非常一致)。

查看挂载好之后的组织形式,发现 ./mnt 中出现了原来两个文件夹的综合内容,其中 common.txt 文件选择的是 top/ 文件夹的。

➜  tree
.
├── base
│   ├── common.txt
│   └── hello.txt
├── mnt
│   ├── common.txt
│   ├── foo.txt
│   └── hello.txt
└── top
    ├── common.txt
    └── foo.txt

➜  cat mnt/common.txt 
top

 

如果要修改 common.txt 文件,会发现只有 top 目录对应的内容发生了变化,base 下面的内容会保持不动:

➜  echo changed > ./mnt/common.txt
➜  cat top/common.txt 
changed
➜  cat base/common.txt 
base

 

  这是因为 aufs 会逐层去查找文件,发现最上层存在文件 common.txt 并且是可写的,就会直接操作这个文件。类似的,如果是修改 foo.txt 也会直接反应在 top/ 目录里面。

但是如果我们想要修改 hello.txt 文件,和预期不一样的是,base/hello.txt 并没有变化,而是新建了一个 top/hello.txt 文件,所有的操作都是在这个文件进行的。实验结果如下:

➜  echo hello, world > mnt/hello.txt 
➜  tree
.
├── base
│   ├── common.txt
│   └── hello.txt
├── mnt
│   ├── common.txt
│   ├── foo.txt
│   └── hello.txt
└── top
    ├── common.txt
    ├── foo.txt
    └── hello.txt

 

  这是因为,aufs 从上往下查找文件,虽然在 base/ 中发现了 hello.txt 文件,但是这个 branch 是以只读的方式挂载的,所以 aufs 并不能直接修改它,而是把它拷贝一份到上层,并对这个拷贝进行修改。

当然我们可以在 mount 的指定每个 branch 的读写模式,比如把两个 branch 都以可写的方式挂载:

sudo mount -t aufs -o br=./top=rw:./base=rw none ./mnt

 

那么修改文件的规则会发生一些变化,文件查找还是从前到后,但是一旦发现文件,就能直接修改这个 branch 的文件内容,而不需要进行拷贝了。具体的实验就不做了,操作也非常简单,读者可以自行完成。

可以指定的权限一共有三种:

  • rw:可读可写,用户能直接修改这个 branch 的文件内容
  • ro:只读,用户不能通过 aufs 的接口对文件进行写操作,只能读取里面的内容
  • rr:real read only,底层的文件本来就是只读的(这种情况比较少见),这种情况下,aufs 就不用担心文件不通过它的接口被修改的情况

除了读写模式之外,还有一个重要的属性——whiteout

通过 aufs 指定的读写模式,只有用户通过最终的挂载点访问才有效,如果用户绕过挂载点,直接修改原来的文件,aufs 应该怎么处理呢?这个行为是由一个参数控制的,udba(全称是 User Direct Branch Access),这个参数有三个可选值:

  • udba=none:aufs 不会进行任何数据同步的检查,因此性能会高一点,但是可能会出现数据不一致的情况。如果用户能保证文件不会直接被修改,或者对文件内容一致性要求不高,可以使用
  • udba=reval:aufs 会检查底层的文件有没有改动,如果有的话,把改动的内容更新到挂载点。这个性能会导致 aufs 产生额外的性能损耗
  • udba=notify:通过 inotify 监听底层的文件变化,基于事件驱动,能够减少第二种方式的性能损耗

说了这么多,可以看出来其实 aufs 最核心的功能还是那句话:把多个目录合并成一个目录,让用户决定在操作统一的文件系统。虽然看起来很有趣,那么 aufs 有哪些实际的用处呢?当然它被我们提起是因为 docker 可以用它来保存镜像和容器,但是 aufs 出现的时间要比 docker 长很多,它常见的用法包括:

  • Linux 光盘演示和教程,录制了 Linux 的光盘可以用来让用户体验,但是光盘的内容是只读的,可以通过 aufs 把光盘和 U 盘或者磁盘 mount 到一起,用户对文件的修改保存到后面的存储上
  • 如果系统上因为各种原因,不同用户的 home 目录保存在不同的路径和磁盘上,可以通过 aufs 把它们 mount 到一起,统一进行操作
posted @ 2022-01-14 17:35  codestacklinuxer  阅读(151)  评论(0)    收藏  举报