Docker存儲驅動之OverlayFS簡介

簡介

  OverlayFS是一種和AUFS很類似的文件系統,與AUFS相比,OverlayFS有以下特性:
   1) 更簡單地設計;
   2) 從3.18開始,就進入了Linux內核主線;
   3) 可能更快一些。
  因此,OverlayFS在Docker社區關注度提高很快,被很多人認爲是AUFS的繼承者。就像宣稱的一樣,OverlayFS還很年輕。所以,在生成環境使用它時,還是需要更加當心。
  Docker的overlay存儲驅動利用了很多OverlayFS特性來構建和管理鏡像與容器的磁盤結構。
  自從Docker1.12起,Docker也支持overlay2存儲驅動,相比於overlay來說,overlay2在inode優化上更加高效。但overlay2驅動只兼容Linux kernel4.0以上的版本。
  注意:自從OverlayFS加入kernel主線後,它在kernel模塊中的名稱就被從overlayfs改爲overlay了。但是爲了在本文中區別,我們使用OverlayFS代表整個文件系統,而overlay/overlay2表示Docker的存儲驅動。

overlay和overlay2

OverlayFS(overlay)的鏡像分層與共享

  OverlayFS使用兩個目錄,把一個目錄置放於另一個之上,並且對外提供單個統一的視角。這兩個目錄通常被稱作層,這個分層的技術被稱作union mount。術語上,下層的目錄叫做lowerdir,上層的叫做upperdir。對外展示的統一視圖稱作merged。
  下圖展示了Docker鏡像和Docker容器是如何分層的。鏡像層就是lowerdir,容器層是upperdir。暴露在外的統一視圖就是所謂的merged。
  OverlayFS and Docker
  注意鏡像層和容器層是如何處理相同的文件的:容器層(upperdir)的文件是顯性的,會隱藏鏡像層(lowerdir)相同文件的存在。容器映射(merged)顯示出統一的視圖。
  overlay驅動只能工作在兩層之上。也就是說多層鏡像不能用多層OverlayFS實現。替代的,每個鏡像層在/var/lib/docker/overlay中用自己的目錄來實現,使用硬鏈接這種有效利用空間的方法,來引用底層分享的數據。注意:Docker1.10之後,鏡像層ID和/var/lib/docker中的目錄名不再一一對應。
  創建一個容器,overlay驅動聯合鏡像層和一個新目錄給容器。鏡像頂層是overlay中的只讀lowerdir,容器的新目錄是可寫的upperdir。

overlay中鏡像和容器的磁盤結構

  下面的docker pull命令展示了Docker host下載一個由5層組成的鏡像。

$ sudo docker pull ubuntu

Using default tag: latest
latest: Pulling from library/ubuntu

5ba4f30e5bea: Pull complete
9d7d19c9dc56: Pull complete
ac6ad7efd0f9: Pull complete
e7491a747824: Pull complete
a3ed95caeb02: Pull complete
Digest: sha256:46fb5d001b88ad904c5c732b086b596b92cfb4a4840a3abd0e35dbb6870585e4
Status: Downloaded newer image for ubuntu:latest

  上圖的輸出結果顯示pull了5個目錄包含了5個鏡像層,每一層在/var/lib/docker/overlay/下都有自己的目錄。還是再次提醒下,如你所見,Docker1.10之後,鏡像層和目錄名不再對應。

$ ls -l /var/lib/docker/overlay/

total 20
drwx------ 3 root root 4096 Jun 20 16:11 38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8
drwx------ 3 root root 4096 Jun 20 16:11 55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
drwx------ 3 root root 4096 Jun 20 16:11 824c8a961a4f5e8fe4f4243dab57c5be798e7fd195f6d88ab06aea92ba931654
drwx------ 3 root root 4096 Jun 20 16:11 ad0fe55125ebf599da124da175174a4b8c1878afe6907bf7c78570341f308461
drwx------ 3 root root 4096 Jun 20 16:11 edab9b5e5bf73f2997524eebeac1de4cf9c8b904fa8ad3ec43b3504196aa3801

  鏡像層目錄中,共享的數據使用的是硬鏈接,他們的inode號相同。這樣做有效地利用了磁盤。

$ ls -i /var/lib/docker/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

19793696 /var/lib/docker/overlay/38f3ed2eac129654acef11c32670b534670c3a06e483fce313d72e3e0a15baa8/root/bin/ls

$ ls -i /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

19793696 /var/lib/docker/overlay/55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358/root/bin/ls

  容器也在/var/lib/docker/overlay/下。使用ls -l命令查看容器目錄,會發現以下文件和目錄。

$ ls -l /var/lib/docker/overlay/<directory-of-running-container>

total 16
-rw-r--r-- 1 root root   64 Jun 20 16:39 lower-id
drwxr-xr-x 1 root root 4096 Jun 20 16:39 merged
drwxr-xr-x 4 root root 4096 Jun 20 16:39 upper
drwx------ 3 root root 4096 Jun 20 16:39 work

  這四個文件系統對象都是OverlayFS的組件。lower-id文件包含了容器的鏡像層最頂層的ID。

$ cat /var/lib/docker/overlay/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id

55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358

  upper目錄是容器的可讀寫層。任何對容器的改變都寫在這個目錄中。
  merged目錄就是容器的mount point,這就是暴露的鏡像(lowerdir)和容器(upperdir)的統一視圖。任何對容器的改變也影響這個目錄。
  work目錄是OverlayFS功能需要的,會被如copy_up之類的操作使用。
  可以通過mount命令來覈實上面的描述是否正確。

$ mount | grep overlay

overlay on /var/lib/docker/overlay/ec444863a55a.../merged
type overlay (rw,relatime,lowerdir=/var/lib/docker/overlay/55f1e14c361b.../root,
upperdir=/var/lib/docker/overlay/ec444863a55a.../upper,
workdir=/var/lib/docker/overlay/ec444863a55a.../work)

OverlayFS(overlay2)的鏡像分層與共享

  overlay驅動只工作在一個lower OverlayFS層之上,因此需要硬鏈接來實現多層鏡像,但overlay2驅動原生地支持多層lower OverlayFS鏡像(最多128層)。
  因此overlay2驅動在合層相關的命令(如build和commit)中提供了更好的性能,與overlay驅動對比,消耗了更少的inode。

overlay2中鏡像和容器的磁盤結構

  docker pull ubuntu下載了包含5層的鏡像,可以看到在/var/lib/docker/overlay2中,有6個目錄。

$ ls -l /var/lib/docker/overlay2

total 24
drwx------ 5 root root 4096 Jun 20 07:36 223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7
drwx------ 3 root root 4096 Jun 20 07:36 3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b
drwx------ 5 root root 4096 Jun 20 07:36 4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1
drwx------ 5 root root 4096 Jun 20 07:36 e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5
drwx------ 5 root root 4096 Jun 20 07:36 eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed
drwx------ 2 root root 4096 Jun 20 07:36 l

  l目錄包含了很多軟連接,使用短名稱指向了其他層。短名稱用於避免mount參數時達到頁面大小的限制。

$ ls -l /var/lib/docker/overlay2/l

total 20
lrwxrwxrwx 1 root root 72 Jun 20 07:36 6Y5IM2XC7TSNIJZZFLJCS6I4I4 -> ../3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 B3WWEFKBG3PLLV737KZFIASSW7 -> ../4e9fa83caff3e8f4cc83693fa407a4a9fac9573deaf481506c102d484dd1e6a1/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 JEYMODZYFCZFYSDABYXD5MF6YO -> ../eca1e4e1694283e001f200a667bb3cb40853cf2d1b12c29feda7422fed78afed/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 NFYKDW6APBCCUCTOUSYDH4DXAT -> ../223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff
lrwxrwxrwx 1 root root 72 Jun 20 07:36 UL2MW33MSE3Q5VYIKBRN4ZAGQP -> ../e8876a226237217ec61c4baf238a32992291d059fdac95ed6303bdff3f59cff5/diff

  在最低層中,有個link文件,包含了前面提到的這個層對應的短名稱;還有個diff目錄,包含了這個鏡像的內容。

$ ls /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/

diff  link

$ cat /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/link

6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls  /var/lib/docker/overlay2/3a36935c9df35472229c57f4a27105a136f5e4dbef0f87905b2e506e494e348b/diff

bin  boot  dev  etc  home  lib  lib64  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

  第二底層中,lower文件指出了該層的組成。該目錄還有diff、merged和work目錄。

$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7

diff  link  lower  merged  work

$ cat /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/lower

l/6Y5IM2XC7TSNIJZZFLJCS6I4I4

$ ls /var/lib/docker/overlay2/223c2864175491657d238e2664251df13b63adb8d050924fd1bfcdb278b866f7/diff/

etc  sbin  usr  var

  運行容器包含的目錄同樣有着類似的文件和目錄。注意在lower文件中,使用:符號來分割不同的底層,並且順序是從高層到底層。

$ ls -l /var/lib/docker/overlay/<directory-of-running-container>

$ cat /var/lib/docker/overlay/<directory-of-running-container>/lower

l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4

  mount的結果如下:

$ mount | grep overlay

overlay on /var/lib/docker/overlay2/9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/merged
type overlay (rw,relatime,
lowerdir=l/DJA75GUWHWG7EWICFYX54FIOVT:l/B3WWEFKBG3PLLV737KZFIASSW7:l/JEYMODZYFCZFYSDABYXD5MF6YO:l/UL2MW33MSE3Q5VYIKBRN4ZAGQP:l/NFYKDW6APBCCUCTOUSYDH4DXAT:l/6Y5IM2XC7TSNIJZZFLJCS6I4I4,
upperdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/diff,
workdir=9186877cdf386d0a3b016149cf30c208f326dca307529e646afce5b3f83f5304/work)

容器使用overlay讀寫

  有三種場景,容器會通過overlay只讀訪問文件。
    容器層不存在的文件。如果容器只讀打開一個文件,但該容器不在容器層(upperdir),就要從鏡像層(lowerdir)中讀取。這會引起很小的性能損耗。
    只存在於容器層的文件。如果容器只讀權限打開一個文件,並且容器只存在於容器層(upperdir)而不是鏡像層(lowerdir),那麼直接從鏡像層讀取文件,無額外性能損耗。
    文件同時存在於容器層和鏡像層。那麼會讀取容器層的文件,因爲容器層(upperdir)隱藏了鏡像層(lowerdir)的同名文件。因此,也沒有額外的性能損耗。
  有以下場景容器修改文件。
    第一次寫一個文件。容器第一次寫一個已經存在的文件,容器層不存在這個文件。overlay/overlay2驅動執行copy-up操作,將文件從鏡像層拷貝到容器層。然後容器修改容器層新拷貝的文件。
    然而,OverlayFS工作在文件級別而不是塊級別。也就是說所有的OverlayFS的copy-up操作都會拷貝整個文件,即使文件非常大但卻只修改了一小部分,這在容器寫性能上有着顯著的影響。不過,有兩個方面值得注意:
     ▷ copy-up操作只發生在第一次寫文件時。後續的對同一個文件的寫操作都是直接針對拷貝到容器層的那個新文件。
     ▷ OverlayFS只工作在兩層中。這比AUFS要在多層鏡像中查找時性能要好。
    刪除文件和目錄。刪除文件時,容器會在鏡像層創建一個whiteout文件,而鏡像層的文件並沒有刪除。但是,whiteout文件會隱藏它。
    容器中刪除一個目錄,容器層會創建一個不透明目錄。這和whiteout文件隱藏鏡像層的文件類似。
    重命名目錄。只有在源路徑和目的路徑都在頂層容器層時,才允許執行rename操作。否則,會返回EXDEV。
    因此,你的應用需要能夠處理EXDEV,並且回滾操作,執行替代的“拷貝和刪除”策略。

在Docker中配置overlay/overlay2存儲驅動

  爲了給Docker配置overlay存儲驅動,你的Docker host必須運行在Linux kernel3.18版本之上,而且加載了overlay內核驅動。對於overlay2驅動,kernel版本必須在4.0或以上。OverlayFS可以運行在大多數Linux文件系統之上。不過,現在最建議在生產環境中使用ext4。
  下面的步驟講述瞭如何在Docker host中配置使用OverlayFS。
  注意:在開始配置之前,如果你已經在使用Docker daemon,並且有一些想保留的鏡像,簡易你push它們到Docker hub中。
    1) 如果Docker daemon正在運行,需要先停止其運行。

$ systemctl stop docker.service

    2) 檢查kernel版本,確認overlay的內核模塊是否加載。

$ uname -r

4.4.0-64-generic

$ lsmod | grep overlay

overlay

# 如果上面命令沒有輸出,說明驅動沒有加載,可以如下操作
$ modprobe overlay

    3) 使用overlay/overlay2存儲驅動來啓動Docker daemon。

$ dockerd --storage-driver=overlay2 &

[1] 29403
root@ip-10-0-0-174:/home/ubuntu# INFO[0000] Listening for HTTP on unix (/var/run/docker.sock)
INFO[0000] Option DefaultDriver: bridge
INFO[0000] Option DefaultNetwork: bridge
<output truncated>

    此外,你還可以在Docker的配置文件中添加–storage-driver=overlay的標誌到DOCKER_OPTS中,這樣就可以持久化配置,不再需要啓動daemon時手動指定–storage-driver標誌了。比如,可以將配置持久化到配置文件/etc/default/docker中,將下面內容加入該文件中。

DOCKER_OPTS="--storage-driver=overlay2"

    4) 檢查daemon是否已經使用了overlay/overlay2存儲驅動。

$ docker info

Containers: 0
Images: 0
Storage Driver: overlay2
Backing Filesystem: extfs
<output truncated>

    注意輸出結果顯示後端文件系統使用的是extfs。雖然支持多種文件系統,但是生產環境中還是建議使用extfs(尤其ext4)。

OverlayFS和Docker性能

  一般來說,overlay/overlay2驅動更快一些,幾乎肯定比aufs和devicemapper更快,在某些情況下,可能比btrfs也更快。即便如此,在使用overlay/overlay2存儲驅動時,還是需要注意以下一些方面:
-   Page Caching,頁緩存。OverlayFS支持頁緩存共享,也就是說如果多個容器訪問同一個文件,可以共享一個或多個頁緩存選項。這使得overlay/overlay2驅動高效地利用了內存,是PaaS平臺或者其他高密度場景的一個很好地選項。
-   copy_up。和AuFS一樣,在容器第一次修改文件時,OverlayFS都需要執行copy-up操作,這會給寫操作帶來一些延遲——尤其這個要拷貝的文件很大時。不過,一旦文件已經執行了這個向上拷貝的操作後,所有後續對這個文件的操作都只針對這份容器層的新拷貝而已。
OverlayFS的copy_up操作比AuFS的copy_up操作要快。因爲AUFS支持比OverlayFS支持更多的層數,如果需要在多層查找文件時,就可能導致比較大的延遲。
-   Inode limits。使用overlay存儲驅動可能導致過多的inode消耗,尤其是Docker host上鏡像和容器的數目增長時。大量的鏡像,或者很多容器啓停,,會迅速消耗掉該Docker host上的inode。overlay2存儲驅動不存在這個問題。
  不幸的是,只能在文件系統創建時指定inode的個數。因此,可以考慮將/var/lib/docker放在一個單獨的設備文件系統中,或者在創建文件系統時指定inode個數。
  以下一些方法可以提供OverlayFS的性能。
-   使用Solid State Devices(SSD)。
-   使用數據卷。數據卷能提高更好的性能,因爲其繞過存儲驅動,不會引起超配、copy-on-write可能會導致的隱患。

OverlayFS兼容性

  有以下兩點OverlayFS和其他文件系統不太兼容:
- open(2)。OverlayFS支持喫POSIX標準的一個子集。以copy-up操作爲例,加入你的應用調用了fd1=open(“foo”, O_RDONLY) 和 fd2=open(“foo”, O_RDWR),你的應用期望fd1和fd2指向同一個文件,然而,因爲copy-up操作,會導致指向不同的文件。
- rename(2),這個和前面提到AuFS一致。

小結

  overlay/overlay2存儲驅動已經成爲了Docker存儲驅動的首選,並且性能優於AuFS和devicemapper。不過,他們也帶來了一些與其他文件系統的不兼容性,如對open和rename操作的支持。另外,overlay與overlay2相比,overlay2支持了多層鏡像,優化了inode使用。然而,使用這兩種驅動時,需要注意你的Docker host的kernel版本。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章