1. 程式人生 > >Docker儲存驅動之AUFS簡介

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對目錄的重新命名支援得不好,在編寫程式時需要注意這點。