AUFS又叫Another UnionFS,後來叫Alternative UnionFS,後來可能以爲不夠霸氣,叫成Advance UnionFS。是個叫Junjiro Okajima(岡島順治郎)在2006年開發的,AUFS徹底重寫了早期的UnionFS 1.x,其主要目的是爲了可靠性和性能,而且引入了一些新的功能,好比可寫分支的負載均衡。AUFS在使用上全兼容UnionFS,並且比以前的UnionFS在穩定性和性能上都要好不少,後來的UnionFS 2.x開始抄AUFS中的功能。可是他竟然沒有進到Linux主幹裏,就是由於Linus不讓,基本上是由於代碼量比較多,並且寫得爛(相對於只有3000行的union mount和10000行的UnionFS,以及其它平均下來只有6000行代碼左右的VFS,AUFS竟然有30000行代碼),因此,岡島不斷地改進代碼質量,不斷地提交,不斷地被Linus拒掉,因此,到今天AUFS都還進不了Linux主幹(今天你能夠看到AUFS的代碼其實還好了,比起OpenSSL好N倍,要麼就是Linus對代碼的質量要求很是高,要麼就是Linus就是不喜歡AUFS)。html
不過,好在有不少發行版都用了AUFS,好比:Ubuntu 10.04,Debian6.0, Gentoo Live CD支持AUFS,因此,也OK了。node
好了,扯完這些閒話,咱們仍是看一個示例吧(環境:Ubuntu 14.04)linux
首先,咱們建上兩個目錄(水果和蔬菜),並在這兩個目錄中放上一些文件,水果中有蘋果和蕃茄,蔬菜有胡蘿蔔和蕃茄。算法
1
2
3
4
5
6
7
8
|
$ tree
.
├── fruits
│ ├── apple
│ └── tomato
└── vegetables
├── carrots
└── tomato
|
而後,咱們輸入如下命令:docker
1
2
3
4
5
6
7
8
9
10
11
12
|
# 建立一個mount目錄
$
mkdir
mnt
# 把水果目錄和蔬菜目錄union mount到 ./mnt目錄中
$
sudo
mount
-t aufs -o
dirs
=.
/fruits
:.
/vegetables
none .
/mnt
# 查看./mnt目錄
$ tree .
/mnt
.
/mnt
├── apple
├── carrots
└── tomato
|
咱們能夠看到在./mnt目錄下有三個文件,蘋果apple、胡蘿蔔carrots和蕃茄tomato。水果和蔬菜的目錄被union到了./mnt目錄下了。shell
咱們來修改一下其中的文件內容:ubuntu
1
2
3
4
5
|
$
echo
mnt > .
/mnt/apple
$
cat
.
/mnt/apple
mnt
$
cat
.
/fruits/apple
mnt
|
上面的示例,咱們能夠看到./mnt/apple的內容改了,./fruits/apple的內容也改了。bash
1
2
3
4
5
|
$
echo
mnt_carrots > .
/mnt/carrots
$
cat
.
/vegetables/carrots
$
cat
.
/fruits/carrots
mnt_carrots
|
上面的示例,咱們能夠看到,咱們修改了./mnt/carrots的文件內容,./vegetables/carrots並無變化,反而是./fruits/carrots的目錄中出現了carrots文件,其內容是咱們在./mnt/carrots裏的內容。app
也就是說,咱們在mount aufs命令中,咱們沒有指它vegetables和fruits的目錄權限,默認上來講,命令行上第一個(最左邊)的目錄是可讀可寫的,後面的全都是隻讀的。(通常來講,最前面的目錄應該是可寫的,然後面的都應該是隻讀的)負載均衡
因此,若是咱們像下面這樣指定權限來mount aufs,你就會發現有不同的效果(記得先把上面./fruits/carrots的文件刪除了):
1
2
3
4
5
6
7
8
9
|
$
sudo
mount
-t aufs -o
dirs
=.
/fruits
=rw:.
/vegetables
=rw none .
/mnt
$
echo
"mnt_carrots"
> .
/mnt/carrots
$
cat
.
/vegetables/carrots
mnt_carrots
$
cat
.
/fruits/carrots
cat
: .
/fruits/carrots
: No such
file
or directory
|
如今,在這狀況下,若是咱們要修改./mnt/tomato這個文件,那麼到底是哪一個文件會被改寫?
1
2
3
4
5
6
7
|
$
echo
"mnt_tomato"
> .
/mnt/tomato
$
cat
.
/fruits/tomato
mnt_tomato
$
cat
.
/vegetables/tomato
I am a vegetable
|
可見,若是有重複的文件名,在mount命令行上,越往前的就優先級越高。
你能夠用這個例子作一些各類各樣的試驗,我這裏主要是給你們一個感性認識,就不展開試驗下去了。
那麼,這種UnionFS有什麼用?
歷史上,有一個叫Knoppix的Linux發行版,其主要用於Linux演示、光盤教學、系統急救,以及商業產品的演示,不須要硬盤安裝,直接把CD/DVD上的image運行在一個可寫的存儲設備上(好比一個U盤上),其實,也就是把CD/DVD這個文件系統和USB這個可寫的系統給聯合mount起來,這樣你對CD/DVD上的image作的任何改動都會在被應用在U盤上,因而乎,你能夠對CD/DVD上的內容進行任意的修改,由於改動都在U盤上,因此你改不壞原來的東西。
咱們能夠再發揮一下想像力,你也能夠把一個目錄,好比你的源代碼,做爲一個只讀的template,和另外一個你的working directory給union在一塊兒,而後你就能夠作各類修改而不用懼怕會把源代碼改壞了。有點像一個ad hoc snapshot。
Docker把UnionFS的想像力發揮到了容器的鏡像。你是否還記得我在介紹Linux Namespace上篇中用mount namespace和chroot山寨了一鏡像。如今當你看過了這個UnionFS的技術後,你是否是就明白了,你徹底能夠用UnionFS這樣的技術作出分層的鏡像來。
下圖來自Docker的官方文檔Layer,其很好的展現了Docker用UnionFS搭建的分層鏡像。
關於docker的分層鏡像,除了aufs,docker還支持btrfs, devicemapper和vfs,你可使用 -s 或 –storage-driver= 選項來指定相關的鏡像存儲。在Ubuntu 14.04下,docker默認Ubuntu的 aufs(在CentOS7下,用的是devicemapper,關於devicemapper,我會以之後的文章中講解)你能夠在下面的目錄中查看相關的每一個層的鏡像:
1
|
/var/lib/docker/aufs/diff/
<
id
>
|
在docker執行起來後(好比:docker run -it ubuntu /bin/bash ),你能夠從/sys/fs/aufs/si_[id]目錄下查看aufs的mount的狀況,下面是個示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#ls /sys/fs/aufs/si_b71b209f85ff8e75/
br0 br2 br4 br6 brid1 brid3 brid5 xi_path
br1 br3 br5 brid0 brid2 brid4 brid6
# cat /sys/fs/aufs/si_b71b209f85ff8e75/*
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7
=rw
/var/lib/docker/aufs/diff/87315f1367e5703f599168d1e17528a0500bd2e2df7d2fe2aaf9595f3697dbd7-init
=ro+wh
/var/lib/docker/aufs/diff/d0955f21bf24f5bfffd32d2d0bb669d0564701c271bc3dfc64cfc5adfdec2d07
=ro+wh
/var/lib/docker/aufs/diff/9fec74352904baf5ab5237caa39a84b0af5c593dc7cc08839e2ba65193024507
=ro+wh
/var/lib/docker/aufs/diff/a1a958a248181c9aa6413848cd67646e5afb9797f1a3da5995c7a636f050f537
=ro+wh
/var/lib/docker/aufs/diff/f3c84ac3a0533f691c9fea4cc2ceaaf43baec22bf8d6a479e069f6d814be9b86
=ro+wh
/var/lib/docker/aufs/diff/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158
=ro+wh
64
65
66
67
68
69
70
/run/shm/aufs
.xino
|
你會看到只有最頂上的層(branch)是rw權限,其它的都是ro+wh權限只讀的。
關於docker的aufs的配置,你能夠在/var/lib/docker/repositories-aufs這個文件中看到。
AUFS有全部Union FS的特性,把多個目錄,合併成同一個目錄,並能夠爲每一個須要合併的目錄指定相應的權限,實時的添加、刪除、修改已經被mount好的目錄。並且,他還能在多個可寫的branch/dir間進行負載均衡。
上面的例子,咱們已經看到AUFS的mount的示例了。下面咱們來看一看被union的目錄(分支)的相關權限:
權限中,咱們看到了一個術語:whiteout,下面我來解釋一下這個術語。
通常來講ro的分支都會有wh的屬性,好比 「[dir]=ro+wh」。所謂whiteout的意思,若是在union中刪除的某個文件,其實是位於一個readonly的分支(目錄)上,那麼,在mount的union這個目錄中你將看不到這個文件,可是read-only這個層上咱們沒法作任何的修改,因此,咱們就須要對這個readonly目錄裏的文件做whiteout。AUFS的whiteout的實現是經過在上層的可寫的目錄下創建對應的whiteout隱藏文件來實現的。
看個例子:
假設咱們有三個目錄和文件以下所示(test是個空目錄):
1
2
3
4
5
6
7
8
9
|
# tree
.
├── fruits
│ ├── apple
│ └── tomato
├──
test
└── vegetables
├── carrots
└── tomato
|
咱們以下mount:
1
2
3
4
5
6
|
# mkdir mnt
# mount -t aufs -o dirs=./test=rw:./fruits=ro:./vegetables=ro none ./mnt
# # ls ./mnt/
apple carrots tomato
|
如今咱們在權限爲rw的test目錄下建個whiteout的隱藏文件.wh.apple,你就會發現./mnt/apple這個文件就消失了:
1
2
3
4
|
# touch ./test/.wh.apple
# ls ./mnt
carrots tomato
|
上面這個操做和 rm ./mnt/apple是同樣的。
Branch – 就是各個要被union起來的目錄(就是我在上面使用的dirs的命令行參數)
Whiteout 和 Opaque
看到上面這些,你必定會有幾個問題:
其1、你可能會問,要有文件在原來的地方被修改了會怎麼樣?mount的目錄會一塊兒改變嗎?答案是會的,也能夠是不會的。由於你能夠指定一個叫udba的參數(全稱:User’s Direct Branch Access),這個參數有三個取值:
其2、若是有多個rw的branch(目錄)被union起來了,那麼,當我建立文件的時候,aufs會建立在哪裏呢? aufs提供了一個叫create的參數能夠供你來配置至關的建立策略,下面有幾個例子。
create=rr | round−robin 輪詢。下面的示例能夠看到,新建立的文件輪流寫到三個目錄中
1
2
3
4
5
6
7
8
9
10
|
hchen$
sudo
mount
-t aufs -o
dirs
=.
/1
=rw:.
/2
=rw:.
/3
=rw -o create=rr none .
/mnt
hchen$
touch
.
/mnt/a
.
/mnt/b
.
/mnt/c
hchen$ tree
.
├── 1
│ └── a
├── 2
│ └── c
└── 3
└── b
|
create=mfs[:second] | most−free−space[:second] 選一個可用空間最好的分支。能夠指定一個檢查可用磁盤空間的時間。
create=mfsrr:low[:second] 選一個空間大於low的branch,若是空間小於low了,那麼aufs會使用 round-robin 方式。
更多的關於AUFS的細節使用參數,你們能夠直接在Ubuntu 14.04下經過 man aufs 來看一下其中的各類參數和命令。
AUFS的性能慢嗎?也慢也不慢。由於AUFS會把全部的分支mount起來,因此,在查找文件上是比較慢了。由於它要遍歷全部的branch。是個O(n)的算法(很明顯,這個算法有很大的改進空間的)因此,branch越多,查找文件的性能也就越慢。可是,一旦AUFS找到了這個文件的inode,那後之後的讀寫和操做原文件基本上是同樣的。
因此,若是你的程序跑在在AUFS下,open和stat操做會有明顯的性能降低,branch越多,性能越差,可是在write/read操做上,性能沒有什麼變化。
IBM的研究中心對Docker的性能給了一份很是不錯的性能報告(PDF)《An Updated Performance Comparison of Virtual Machinesand Linux Containers》
我截了兩張圖出來,第一張是順序讀寫,第二張是隨機讀寫。基本沒有什麼性能損失的問題。而KVM在隨機讀寫的狀況也就有點慢了(可是,若是硬盤是SSD的呢?)
順序讀寫
隨機讀寫