aufs的全稱是advanced multi-layered unification filesystem,主要功能是把多個文件夾的內容合併到一塊兒,提供一個統一的視圖,主要用於各個Linux發行版的livecd中,以及docker裏面用來組織image。html
聽說因爲aufs代碼的可維護性很差(代碼可讀性和註釋不太好),因此一直沒有被合併到Linux內核的主線中去,不過有些發行版的kernel裏面維護的有該文件系統,好比在ubuntu 16.04的內核代碼中,就有該文件系統。node
本篇全部例子都在ubuntu-server-x86_64 16.04下執行經過linux
在使用aufs以前,能夠經過下面的命令確認當前系統是否支持aufs,若是不支持,請自行根據相應發行版的文檔安裝docker
#下面的命令若是沒有輸出,表示內核不支持aufs #因爲ubuntu 16.04的內核中已經將aufs編譯進去了,因此默認就支持 dev@ubuntu:~$ grep aufs /proc/filesystems nodev aufs #這裏nodev表示該文件系統不須要建在設備上
注意:有些Linux發行版可能將aufs編譯成了模塊,因此雖然這裏顯示內核不支持,但其實後面的命令都能正常運行ubuntu
選擇好相應的參數(參考幫助文檔),調用mount命令便可,示例以下bash
# mount -t aufs -o br=./Branch-0:./Branch-1:./Branch-2 none ./MountPoint
-t aufs: 指定掛載類型爲aufs性能
-o br=./Branch-0:./Branch-1:./Branch-2: 表示將當前目錄下的Branch-0,Branch-1,Branch-2三個文件夾聯合到一塊兒.net
none:aufs不須要設備,只依賴於-o br指定的文件夾,因此這裏填none便可code
./MountPoint:表示將最後聯合的結果掛載到當前的MountPoint目錄下,而後咱們就能夠往這個目錄裏面讀寫文件了server
假設Branch-0裏面有文件001.txt、003.txt,Branch-1裏面有文件001.txt、003.txt、004.txt,Branch-2裏面有文件002.txt、003.txt。
mount完成後,獲得的結果將會以下圖所示
/*001.txt(b0)表示Branch-0的001.txt文件,其它的以此類推*/ +-------------+-------------+-------------+-------------+ MountPoint | 001.txt(b0) | 002.txt(b2) | 003.txt(b0) | 004.txt(b1) | +-------------+-------------+-------------+-------------+ ↑ ↑ ↑ ↑ | | | | +-------------+-------------+-------------+-------------+ Branch-0 | 001.txt | | 003.txt | | +-------------+-------------+-------------+-------------+ Branch-1 | 001.txt | | 003.txt | 004.txt | +-------------+-------------+-------------+-------------+ Branch-2 | | 002.txt | 003.txt | | +-------------+-------------+-------------+-------------+
聯合以後,在MountPoint下將會看到四個文件,分別是Branch-0下的001.txt、003.txt,Branch-1下的04.txt,以及Branch-2下的002.txt。
branch是aufs裏面的概念,其實一個branch就是一個目錄,因此上面的Branch-0,1,2就是三個目錄
branch是有index的,index越小的branch會放在最上面,若是多個branch裏面有一樣的文件,只有index最小的那個branch下的文件纔會被訪問到
MountPoint就是最後這三個目錄聯合後掛載到的位置,訪問這個目錄下的文件都會通過aufs文件系統,換句話說,直接訪問Branch-0,1,2這三個目錄的話,aufs是不知道的
注意:並非全部文件系統裏的目錄都能做爲aufs的branch,目前aufs不支持的有:btrfs aufs eCryptfs
讀這些文件的時候訪問的是最上層的文件,但若是要寫這些文件呢?或者在掛載點下建立新的文件呢?請看下面的示例
掛載時,能夠指定每一個branch的讀寫權限,若是不指定的話,第一個目錄將會是可寫的,其它的目錄是隻讀的,在實際使用時,最好是顯示的指定每一個branch的讀寫屬性,這樣你們都一眼就能看懂。這裏先演示一下只讀掛載:
#準備相應的目錄和文件 dev@ubuntu:~$ mkdir /tmp/aufs && cd /tmp/aufs dev@ubuntu:/tmp/aufs$ mkdir dir0 dir1 root dev@ubuntu:/tmp/aufs$ echo dir0 > dir0/001.txt dev@ubuntu:/tmp/aufs$ echo dir0 > dir0/002.txt dev@ubuntu:/tmp/aufs$ echo dir1 > dir1/002.txt dev@ubuntu:/tmp/aufs$ echo dir1 > dir1/003.txt #最後用tree命令來看看最終的目錄結構 dev@ubuntu:/tmp/aufs$ tree . ├── dir0 │ ├── 001.txt │ └── 002.txt ├── dir1 │ ├── 002.txt │ └── 003.txt └── root #經過指定ro參數來讓兩個branch都爲只讀 dev@ubuntu:/tmp/aufs$ sudo mount -t aufs -o br=./dir0=ro:./dir1=ro none ./root #聯合後最終的root目錄下將看到三個文件 dev@ubuntu:/tmp/aufs$ ls root/ 001.txt 002.txt 003.txt #其中002.txt的內容是dir0中的002.txt的內容,說明dir0的index要比dir1的index小 dev@ubuntu:/tmp/aufs$ cat root/002.txt dir0 #因爲是隻讀掛載,因此touch失敗 dev@ubuntu:/tmp/aufs$ touch root/001.txt touch: cannot touch 'root/001.txt': Read-only file system dev@ubuntu:/tmp/aufs$ touch root/003.txt touch: cannot touch 'root/003.txt': Read-only file system #可是咱們能夠跳過root目錄來修改001.txt和003.txt, #由於跳過了root目錄,因此就不受aufs控制 dev@ubuntu:/tmp/aufs$ touch dir0/001.txt dev@ubuntu:/tmp/aufs$ touch dir1/003.txt #咱們還能在下面的目錄中建立新的文件 dev@ubuntu:/tmp/aufs$ touch dir1/004.txt #新建立的文件能及時的反應到掛載點上去 dev@ubuntu:/tmp/aufs$ ls ./root/ 001.txt 002.txt 003.txt 004.txt #刪除該文件,以避免影響後續的演示 dev@ubuntu:/tmp/aufs$ rm ./dir1/004.txt
從上面的演示能夠看出,咱們能夠跳過掛載點直接讀寫底層的目錄,這樣就不受aufs的控制,但咱們修改的內容(dir1裏面建立的004.txt)仍是能在掛載點下看到,這是由於aufs在訪問文件時,默認的作法是若是最上層目錄裏面沒這個文件,就一層一層的往下找,因此下層有變更的話,aufs會自動發現。控制這種行爲的參數爲「udba」,有興趣能夠參考幫助文檔
因爲訪問一個文件時須要一級一級往下找,因此若是聯合的目錄(層級)過多的話,會影響性能
若是聯合的文件夾有寫的權限,那麼全部的修改都會寫入可寫的那個文件夾,若是可寫的文件夾有多個,那麼寫入哪一個文件夾就依賴於相應的策略,有round-robin、最多剩餘空間等,詳情請參考幫助文檔中的「create」參數,這裏不作介紹。
dev@ubuntu:/tmp/aufs$ sudo umount ./root #dir0具備讀寫權限,dir1爲只讀權限 dev@ubuntu:/tmp/aufs$ sudo mount -t aufs -o br=./dir0=rw:./dir1=ro none ./root dev@ubuntu:/tmp/aufs$ echo "root->write" >> ./root/001.txt dev@ubuntu:/tmp/aufs$ echo "root->write" >> ./root/002.txt dev@ubuntu:/tmp/aufs$ echo "root->write" >> ./root/003.txt dev@ubuntu:/tmp/aufs$ echo "root->write" >> ./root/005.txt #跟開始前相比,dir0目錄下多了003.txt和005.txt,其它的保持不變 dev@ubuntu:/tmp/aufs$ ls ./root/ 001.txt 002.txt 003.txt 005.txt dev@ubuntu:/tmp/aufs$ ls ./dir0/ 001.txt 002.txt 003.txt 005.txt dev@ubuntu:/tmp/aufs$ ls ./dir1/ 002.txt 003.txt #再來看看內容,dir1裏面的內容保持不變 dev@ubuntu:/tmp/aufs$ cat ./dir1/002.txt dir1 dev@ubuntu:/tmp/aufs$ cat ./dir1/003.txt dir1 #dir0下的文件內容都變了 dev@ubuntu:/tmp/aufs$ cat ./dir0/001.txt dir0 root->write dev@ubuntu:/tmp/aufs$ cat ./dir0/002.txt dir0 root->write dev@ubuntu:/tmp/aufs$ cat ./dir0/003.txt dir1 root->write dev@ubuntu:/tmp/aufs$ cat ./dir0/005.txt root->write
當建立一個新文件的時候,新的文件會寫入具備rw權限的那個目錄,若是有多個目錄具備rw權限,那麼依賴於掛載時配置的的建立策略
當修改一個具備rw權限目錄下的文件時,直接修改該文件
當修改一個只有ro權限目錄下的文件時,aufs會先將該文件拷貝到一個rw權限的目錄裏面,而後在上面進行修改,這就是所謂的COW(copy on write),拷貝的速度依賴於底層branch所在的文件系統。
從上面能夠看出,COW對於大文件來講,性能仍是很低的,同時也會佔用不少的空間,但因爲只須要在第一次修改的時候拷貝一次,因此不少狀況下仍是能接受。
刪除文件時,若是該文件只在rw目錄下有,那就直接刪除rw目錄下的該文件,若是該文件在ro目錄下有,那麼aufs將會在rw目錄裏面建立一個.wh開頭的文件,標識該文件已被刪除
#經過aufs刪除全部文件 dev@ubuntu:/tmp/aufs$ rm ./root/001.txt ./root/002.txt ./root/003.txt ./root/005.txt #dir0下的文件全被刪除了,但dir1目錄下的文件沒動 dev@ubuntu:/tmp/aufs$ tree . ├── dir0 ├── dir1 │ ├── 002.txt │ └── 003.txt └── root #經過-a參數來看看dir0目錄下的內容 #能夠看到aufs爲002.txt和003.txt新建了兩個特殊的以.wh開頭的文件, #用來表示這兩個文件已經被刪掉了 #這裏其餘.wh開頭的文件都是aufs用到的一些屬性文件 dev@ubuntu:/tmp/aufs$ ls ./dir0/ -a . .. .wh.002.txt .wh.003.txt .wh..wh.aufs .wh..wh.orph .wh..wh.plnk
這裏只介紹了aufs的基本功能,其它的高級配置項沒有涉及,好比動態的增長和刪除branch等。
使用aufs時,建議參考livecd及docker的使用方式,就是將全部的目錄都以只讀的方式和一個支持讀寫的空目錄聯合起來,這樣全部的修改都會存到那個指定的空目錄中,不用以後刪除掉那個目錄就能夠了,而且在使用的過程當中不要繞過aufs直接操做底層的branch,也不要動態的增長和刪除branch,若是把使用場景弄得太複雜,因爲aufs裏面的細節不少,頗有可能會因爲對aufs的理解不深而踩坑。