[mydocker]---通过例子理解存储驱动AUFS

前言

Docker内置多种存储驱动. 最开始采用AUFS作为文件系统, 其分层概念实现了多个Container可以共享同一个image. 由于AUFS未并入Linux内核, 且只支持Ubuntu, 因此Docker 0.7版本中引入了存储驱动, 目前Docker支持5中存储驱动.

文件系统/存储 存储驱动名称
OverlayFs overlay/overlay2
AUFS aufs
Btrfs btrfs
Device Mapper devicemapper
VFS vfs
ZFS zfs

本文主要介绍AUFS, 会先通过一个例子来理解AUFS是如何工作的, 最后会解释其原理.

AUFS

AUFS能透明覆盖一或多个现有文件系统的层状文件系统,把多层合并成文件系统的单层表示.

例子

root@nicktming:~/aufs# pwd
/root/aufs
root@nicktming:~/aufs# ls 
run.sh
root@nicktming:~/aufs# cat run.sh
mkdir container-layer 
echo "I am container-layer" > container-layer/container-layer.txt

mkdir mnt

for i in {1..3}
do 
mkdir -p image-layer$i/subdir$i
echo "I am image layer $i" > image-layer$i/image-layer$i.txt
echo "subdir $i" > image-layer$i/subdir$i/subdir$i.txt
done
root@nicktming:~/aufs# ./run.sh 
root@nicktming:~/aufs# tree
.
|-- container-layer
|   `-- container-layer.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
`-- run.sh

8 directories, 8 files

可以看到当前aufs文件夹的目录结构. 并且每个文件的内容如下:

root@nicktming:~/aufs# cat container-layer/container-layer.txt 
I am container-layer
root@nicktming:~/aufs# cat image-layer1/image-layer1.txt 
I am image layer 1
root@nicktming:~/aufs# cat image-layer1/subdir1/subdir1.txt 
subdir 1
root@nicktming:~/aufs# cat image-layer2/image-layer2.txt 
I am image layer 2
root@nicktming:~/aufs# cat image-layer2/subdir2/subdir2.txt 
subdir 2
root@nicktming:~/aufs# cat image-layer3/image-layer3.txt 
I am image layer 3
root@nicktming:~/aufs# cat image-layer3/subdir3/subdir3.txt 
subdir 3
root@nicktming:~/aufs# ls mnt/
root@nicktming:~/aufs# 

可以将这些文件目录联合起来挂载到mnt目录下.

root@nicktming:~/aufs# mount -t aufs -o dirs=./container-layer:./image-layer1:./image-layer2:./image-layer3 none ./mnt
root@nicktming:~/aufs# cat /sys/fs/aufs/
config               si_e9a1e7a68699fcc6/ 
root@nicktming:~/aufs# cat /sys/fs/aufs/si_e9a1e7a68699fcc6/*
/root/aufs/container-layer=rw
/root/aufs/image-layer1=ro
/root/aufs/image-layer2=ro
/root/aufs/image-layer3=ro
64
65
66
67
/root/aufs/container-layer/.aufs.xino

可以看到aufs文件系统会默认把dirs后的第一个文件设置为可读写, 其余文件设置为只读. 接下来看一下整个目录结构.

root@nicktming:~/aufs# tree
.
|-- container-layer
|   `-- container-layer.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
|   |-- container-layer.txt
|   |-- image-layer1.txt
|   |-- image-layer2.txt
|   |-- image-layer3.txt
|   |-- subdir1
|   |   `-- subdir1.txt
|   |-- subdir2
|   |   `-- subdir2.txt
|   `-- subdir3
|       `-- subdir3.txt
`-- run.sh

11 directories, 15 files

可以看到挂载点mnt中已经有每个被挂载的文件, 也就是说将不同目录挂载到同一个虚拟文件系统. 无论底下有多少层都是只读的,只有最上层的文件系统是课写的, 也就是这里的container-layer.

layer.png

将多个目录合并成一个虚拟文件系统,成员目录称为虚拟文件系统的一个分支(branch). 也就是说container-layer, image-layer1, image-layer2, image-layer3都被称为branch. 每个branch3个权限, 只读(ro),读写(rw),写隐藏(wo). 一般情况下,aufs只有最上层的branch(在这里是container-layer)有读写权限, 其余branch为只读权限.

6791554437422_.pic.jpg

如果增加一层的话,也只有最顶层的文件有可读写权限.


6771554437359_.pic.jpg

mnt称为挂载点, 用户做操作是在mnt挂载点上做操作. 接下来可以做些简单的操作来看看做些文件是如何变化的.

修改

修改image-layer1.txt中的内容.

root@nicktming:~/aufs# cat mnt/image-layer1.txt 
I am image layer 1
root@nicktming:~/aufs# echo "\n write something to image/layer1/image-layer1.txt\n" >> mnt/image-layer1.txt
root@nicktming:~/aufs# cat mnt/image-layer1.txt 
I am image layer 1
\n write something to image/layer1/image-layer1.txt\n

可以看到mnt/image-layer1.txt中的内容确实发生了变化, 接下来看看image-layer1/image-layer1.txt中的内容是否发生了改变.

root@nicktming:~/aufs# cat image-layer1/image-layer1.txt 
I am image layer 1

可以看到image-layer1/image-layer1.txt中的内容没有丝毫改变. 因为mnt只是个挂载点, 当取消挂载的时候mnt里面的内容都会没有了的,那真正写上去的内容在哪里呢?此时查看一下整个目录的结构.

root@nicktming:~/aufs# tree
.
|-- container-layer
|   |-- container-layer.txt
|   `-- image-layer1.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
|   |-- container-layer.txt
|   |-- image-layer1.txt
|   |-- image-layer2.txt
|   |-- image-layer3.txt
|   |-- subdir1
|   |   `-- subdir1.txt
|   |-- subdir2
|   |   `-- subdir2.txt
|   `-- subdir3
|       `-- subdir3.txt
`-- run.sh

11 directories, 16 files

可以看到container-layer文件夹下面多了一个image-layer1.txt, 查看里面的内容.

root@nicktming:~/aufs# cat container-layer/image-layer1.txt 
I am image layer 1
\n write something to image/layer1/image-layer1.txt\n

发现container-layer/image-layer1.txt正是所要的修改. 从这里可以看到container-layer确实可读写的, image-layer1是只读.

mnt.png

user的角度可以看到所有被挂载的文件, 当修改mntimage-layer1.txt时, 可读写层也就是container-layer会从只读层也就是image-layer1中把对应的image-layer1.txt复制到可写层container-layer并且修改, 当user看到文件的时候读到的container-layerimage-layer1.txt, 因为此时container/image-layer1.txt会覆盖image-layer1/image-layer1.txt, 但是image-layer1/image-layer1.txt并没有做任何改变, 整个image-layer1层没有做任何改变. 如下图所示:

update.png
删除

删除mnt/image-layer2.txt看看会有什么改变.

root@nicktming:~/aufs# rm mnt/image-layer2.txt 
root@nicktming:~/aufs# cat mnt/image-layer2.txt
cat: mnt/image-layer2.txt: No such file or directory
root@nicktming:~/aufs# cat image-layer2/image-layer2.txt 
I am image layer 2
root@nicktming:~/aufs# tree
.
|-- container-layer
|   |-- container-layer.txt
|   `-- image-layer1.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
|   |-- container-layer.txt
|   |-- image-layer1.txt
|   |-- image-layer3.txt
|   |-- subdir1
|   |   `-- subdir1.txt
|   |-- subdir2
|   |   `-- subdir2.txt
|   `-- subdir3
|       `-- subdir3.txt
`-- run.sh

11 directories, 15 files

发现mnt目录下看不到image-layer2.txt, 但是image-layer2层的image-layer2.txt仍然存在, 所以可以说只是逻辑删除了该image-layer2.txt文件, 或者是此aufs做了什么操作让用户看不到该image-layer2.txt文件.

原因: 因为删除的image-layer2.txt是属于镜像层文件, 容器层container-layer会创建一个.wh前缀的隐藏文件, 从而实现对image-layer2.txt的隐藏.

root@nicktming:~/aufs# ls -la container-layer/
total 24
drwxr-xr-x 4 root root 4096 Apr  5 14:44 .
drwxr-xr-x 7 root root 4096 Apr  5 11:12 ..
-rw-r--r-- 1 root root   21 Apr  5 11:12 container-layer.txt
-rw-r--r-- 1 root root   73 Apr  5 13:44 image-layer1.txt
-r--r--r-- 2 root root    0 Apr  5 11:15 .wh.image-layer2.txt
-r--r--r-- 2 root root    0 Apr  5 11:15 .wh..wh.aufs
drwx------ 2 root root 4096 Apr  5 11:15 .wh..wh.orph
drwx------ 2 root root 4096 Apr  5 11:15 .wh..wh.plnk
delete.png
增加

mnt中增加文件. 基于上面的知识, 可以知道创建的文件肯定会存在于container-layer中, 并且也是在容器层container-layer中创建的.

root@nicktming:~/aufs# echo "container-01" > mnt/container-test.txt
root@nicktming:~/aufs# cat mnt/container-test.txt 
container-01
root@nicktming:~/aufs# cat container-layer/container-test.txt 
container-01
root@nicktming:~/aufs# tree 
.
|-- container-layer
|   |-- container-layer.txt
|   |-- container-test.txt
|   `-- image-layer1.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
|   |-- container-layer.txt
|   |-- container-test.txt
|   |-- image-layer1.txt
|   |-- image-layer3.txt
|   |-- subdir1
|   |   `-- subdir1.txt
|   |-- subdir2
|   |   `-- subdir2.txt
|   `-- subdir3
|       `-- subdir3.txt
`-- run.sh

11 directories, 17 files
图片.png

可以看到在容器层container-layer中增加删除修改容器层的文件是不会影响到镜像层中的任何内容的. 由此可以达到根据一个image启动多个容器的目的.

containers.png
umount
root@nicktming:~/aufs# df -h
df: ‘/tmp/tmp5RAi0E’: No such file or directory
Filesystem      Size  Used Avail Use% Mounted on
/dev/vda1        50G  2.7G   45G   6% /
none            4.0K     0  4.0K   0% /sys/fs/cgroup
udev            487M   12K  487M   1% /dev
tmpfs           100M  356K  100M   1% /run
none            5.0M     0  5.0M   0% /run/lock
none            497M   24K  497M   1% /run/shm
none            100M     0  100M   0% /run/user
none             50G  2.7G   45G   6% /root/aufs/mnt
root@nicktming:~/aufs# umount /root/aufs/mnt 
root@nicktming:~/aufs# tree
.
|-- container-layer
|   |-- container-layer.txt
|   |-- container-test.txt
|   `-- image-layer1.txt
|-- image-layer1
|   |-- image-layer1.txt
|   `-- subdir1
|       `-- subdir1.txt
|-- image-layer2
|   |-- image-layer2.txt
|   `-- subdir2
|       `-- subdir2.txt
|-- image-layer3
|   |-- image-layer3.txt
|   `-- subdir3
|       `-- subdir3.txt
|-- mnt
`-- run.sh

8 directories, 10 files

可以看到umount之后mnt里面没有任何内容了, 所有内容保存在了container-layer之中了.

原理

通过上面的例子基本上可以理解AUFS是如何工作的, 其实其涉及到的技术为写时复制(copy-on-write).

写时复制

是一种对可修改资源实现高效复制的资源管理技术. 思想为如果一个资源是重复的并且没有任何修改,这时并不需要立即创建一个新的资源, 因为这个资源可以被新旧实例共享. 创建新资源发生在第一次写操作, 也就是对资源进行修改的时候.

比如对一个image可以启动多个容器, 多个容器可以共享镜像层的文件, 这样可以减少大量的磁盘空间, 但是当某个容器的容器层需要对镜像层的文件进行修改的时候, 此时该容器的容器层会复制一份镜像层中此文件到容器层, 但是别的容器还是可以共享此镜像层的这个文件并不需要创建. 使用CoW可以有效的提高磁盘的利用率.

参考

1. https://blog.csdn.net/yourun_cloud/article/details/62883721
2. http://dockone.io/article/1513
3. 自己动手写docker.(基本参考此书,加入一些自己的理解,加深对docker的理解)

全部内容

mydocker.png

1. [mydocker]---环境说明
2. [mydocker]---urfave cli 理解
3. [mydocker]---Linux Namespace
4. [mydocker]---Linux Cgroup
5. [mydocker]---构造容器01-实现run命令
6. [mydocker]---构造容器02-实现资源限制01
7. [mydocker]---构造容器02-实现资源限制02
8. [mydocker]---构造容器03-实现增加管道
9. [mydocker]---通过例子理解存储驱动AUFS
10. [mydocker]---通过例子理解chroot 和 pivot_root
11. [mydocker]---一步步实现使用busybox创建容器
12. [mydocker]---一步步实现使用AUFS包装busybox
13. [mydocker]---一步步实现volume操作
14. [mydocker]---实现保存镜像
15. [mydocker]---实现容器的后台运行
16. [mydocker]---实现查看运行中容器
17. [mydocker]---实现查看容器日志
18. [mydocker]---实现进入容器Namespace
19. [mydocker]---实现停止容器
20. [mydocker]---实现删除容器
21. [mydocker]---实现容器层隔离
22. [mydocker]---实现通过容器制作镜像
23. [mydocker]---实现cp操作
24. [mydocker]---实现容器指定环境变量
25. [mydocker]---网际协议IP
26. [mydocker]---网络虚拟设备veth bridge iptables
27. [mydocker]---docker的四种网络模型与原理实现(1)
28. [mydocker]---docker的四种网络模型与原理实现(2)
29. [mydocker]---容器地址分配
30. [mydocker]---网络net/netlink api 使用解析
31. [mydocker]---网络实现
32. [mydocker]---网络实现测试

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 193,968评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,682评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,254评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,074评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,964评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,055评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,484评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,170评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,433评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,512评论 2 308
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,296评论 1 325
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,184评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,545评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,150评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,437评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,630评论 2 335

推荐阅读更多精彩内容