Docker存儲驅動之AUFS簡介

簡介

  AUFS曾是Docker默認的首選存儲驅動。它非常穩定、有很多真實場景的部署、很強的社區支持。它有以下主要優點:
  極短的容器啓動時間。
  有效的存儲利用率。
  有效的內存利用率。
  雖然如此,但由於它沒有包含在Linux內核主線中,所有很多Linux發行版並不支持AUFS。
  以下章節介紹AUFS的特性,並且它們如何作用於Docker。

特性

鏡像分層和部署

  AUFS是一種聯合文件系統。它使用同一個Linux host上的多個目錄,逐個堆疊起來,對外呈現出一個統一的文件系統。AUFS使用該特性,實現了Docker鏡像的分層。下圖展示出ubuntu:latest的鏡像的分層。
  image
  注意:在Docker1.10之前,layer的ID對應着其在/var/lib/docker下的目錄名稱,但在Docker1.10之後,不再有這種直接的對應關係。
  對於一個容器來說,只有頂層的容器layer是可讀寫的,而下面的layer都是隻讀的。

讀寫文件

  Docker使用AUFS的CoW(Copy-on-Write)技術來實現鏡像共享和最小化磁盤空間的使用。AUFS作用於文件層,也就是說AUFS CoW拷貝整個文件——即使文件只修改了一點點的內容。所以,它對容器的性能影響很明顯,尤其拷貝多層鏡像下的大文件,或者是在一個深層次的目錄樹中進行搜索。
  不過,在給定的容器中,這種拷貝到頂層layer的操作,每個文件只會做一次。隨後,對該文件的讀寫操作,都只針對容器頂層可讀寫layer的拷貝文件。

刪除文件

  通過上面的介紹,很容易想到。如果要在容器中刪除一個非頂層layer的文件,肯定不會在下層layer中直接刪除,因爲下層layer對於容器來說都是隻讀的。AUFS存儲驅動要刪除一個文件,是通過在容器頂層layer增加一個whiteout文件來實現的。這個whiteout文件可以隱藏下層只讀layer中文件的存在,容器感知不到只讀層layer中文的存在。事實上,無論該文件在下層只讀layer中是否還存在,容器都認爲這個文件被刪除了。下圖展示了whiteout文件如何工作的:
  image

重命名目錄

  AUFS未能完美的支持rename(2)重命名操作,會返回EXDEV[“cross-device link not permitted”],即使源路徑和目的路徑都在同一個AUFS層。因此,你的應用需要能處理EXDEV,可以用“拷貝再刪除”的策略來替代rename操作。
  我在這裏做了一個測試,寫了一個簡單地C程序,該程序將目錄test重命名爲目錄gaga,並打印出rename的結果。該程序在普通服務器上完美運行,那麼在容器中呢?開始做測試吧。

創建docker build目錄,進入該目錄。並在該目錄下創建子目錄test。

$ mkdir build-rename
$ cd build-rename
$ mkdir test

創建文件test.c

$ vim test.c

#include<stdio.h>
#include <fcntl.h>
int main(void)
{
    char oldname[100] = "test", newname[100]="gaga";
    int ret = rename(oldname, newname);
    if (ret == 0)
        printf("rename ok.\n");
    else
        printf("ret = %d\n", ret);
    return 0;
}

  編譯該程序,生成可執行文件a.out。

$ gcc test.c

創建Dockerfile

$ vim Dockerfile

FROM ubuntu
WORKDIR /usr/src/app
COPY ./* /usr/src/app/
CMD /usr/src/app/a.out

生成鏡像。

$ docker build -t rename:v1.0 ./

運行容器

$ docker run --rm rename:v1.0
ret = -1

  該容器啓動後會執行可執行文件a.out,重命名一個目錄。可見結果,rename重命名一個目錄的確是返回了失敗。

配置AUFS

準備

  只有在OS安裝了AUFS的情況下才能使用AUFS存儲驅動,一般來說,Debian/Ubuntu都支持AUFS,而Redhat/CentOS都不支持AUFS。所以,你需要先查看下你的系統是否安裝了AUFS。

$ grep aufs /proc/filesystems
nodev   aufs

  如果以上命令有輸出則表示支持AUFS,否則就說明還未安裝AUFS。可執行以下步驟:
  a. 升級你係統的kernel版本到3.13或者更高,另外建議安裝kernel headers;
  b. 對於Ubuntu/Debian:安裝linux-image-extra-*包:

$ apt-get install linux-image-extra-$(uname -r) \
                       linux-image-extra-virtual

配置

  如果上述操作無誤,就可以使用AUFS來作爲你Docker Daemon的存儲驅動了。

$ dockerd --storage-driver=aufs &

  如果想持久化這個配置,可以編輯你的Docker配置文件(如/etc/default/docker,雖然官方已經不建議使用該文件了),並加入–storage-driver=aufs選項到DOCKER_OPTS中。

# Use DOCKER_OPTS to modify the daemon startup options.
DOCKER_OPTS="--storage-driver=aufs"

  重啓docker daemon(systemctl restart docker.service)後,確認默認存儲驅動是否配置成功:

$ docker info | grep "Storage Driver"

Storage Driver: aufs

本地存儲和AUFS

  當dockerd使用AUFS驅動時,驅動把鏡像和容器存儲在Docker host的本地存儲下:/var/lib/docker/aufs。

鏡像

  鏡像層存儲在/var/lib/docker/aufs/diff裏。Docker 1.10之後,鏡像對應的目錄名稱不再和鏡像ID意義對應了。
  /var/lib/docker/aufs/layers/目錄保存了元數據信息,這些元數據顯示了image層是如何疊加的。該目錄下的每個文件,對應了一個層,而這個文件的內容就是該層之下的層。如:

$ cat /var/lib/docker/aufs/layers/91e54dfb11794fad694460162bf0cb0a4fa710cfa3f60979c177d920813e267c

d74508fb6632491cea586a1fd7d748dfc5274cd6fdfedee309ecdcbc2bf5cb82
c22013c8472965aa5b62559f2b540cd440716ef149756e7b958a1b2aba421e87
d3a1f33e8a5a513092f01bb7eb1c2abf4d711e5105390a3fe1ae2248cfde1391

  由於base layer之下不再有其它層,所有base layer對應的文件內容是空的。

容器

  運行中的容器映射在 /var/lib/docker/aufs/mnt/下,這就是AUFS給容器和它下層layer的一個mount point。如果容器沒有運行了,依然還有這個目錄,但卻是個空目錄,因爲AUFS只在容器運行是才映射。Docker 1.10之上的版本,目錄名同樣不和容器ID對應。
  容器元數據和多種配置文件存放在該目錄下。

$ ls /var/lib/docker/aufs/mnt/670e0053b2ba02ab33dc24daca293e200aa98e871cefec016a5cbf9d41b7cfbf
bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

  容器的可寫層存儲在目錄 /var/lib/docker/aufs/diff/,即使容器停止了,容器對應的目錄依然存在。只有刪除容器時,對應的目錄纔會刪除。

AUFS在Docker中的性能

  對於PaaS層來說,AUFS存儲驅動是一個很好的選擇。因爲AUFS有效地在多個運行容器中共享鏡像,加速了容器啓動時間,減少了容器使用的磁盤空間。
  AUFS在多個鏡像層和容器間分享文件所使用的底層機制,高效地使用了系統的頁緩存。
  同時,AUFS存儲驅動也帶來了一些容器寫性能上的隱患。這是因爲,容器第一次對任何文件的修改,都需要先定位到文件的所在的鏡像層次,並拷貝到容器最頂層的讀寫層。尤其當這些文件存在於很底層,或者文件本身非常大時,性能問題尤其嚴重。

小結

  AUFS是Docker在Ubuntu/Debian中的默認存儲驅動,雖然後面可能會被替換掉。但暫時來說,它完美地契合Docker的特性。並且,如何合理使用,其性能非常優異。另外,需要注意的是,AUFS對目錄的重命名支持得不好,在編寫程序時需要注意這點。

發佈了122 篇原創文章 · 獲贊 55 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章