Docker的OverlayFS儲存驅動
OverlayFS儲存驅動
OverlayFS是一個現代的Union Filesystem,類似於AUFS,但速度更快,實現更簡單。Docker為OverlayFS提供了兩個儲存驅動程式:overlay,以及更新和更穩定的overlay2。(本次主題在Linux核心中對應的驅動是OverlayFS,在Docker中對應的儲存驅動是overlay或overlay2)
注意:如果你的Linux使用的是OverlayFS,請使用overlay2作為驅動而不是overlay,因為overlay2在inode利用率上更高效。使用overlay2要求Linux核心版本在4.0或者更高。
先決條件
OverlayFS是Docker推薦的儲存驅動,但在使用前,需要滿足如下先決條件:
● Linux核心版本需要為4.0或者更高。RHEL和CentOS的版本需要為3.10.0-514或者更高。如果我們使用比較老的核心,我們需要使用不推薦的overlay驅動。
● 當d_type=true時,overlay和overlay2才被xfs備份檔案系統支援。
使用xfs_info來驗證ftype選擇是否設定為1。為了正確格式化xfs檔案系統,需要使用標誌-n ftype=1。
d_type 是 Linux 核心的一個術語,表示 “目錄條目型別”,而目錄條目,其實是檔案系統上目錄資訊的一個數據結構。d_type,就是這個資料結構的一個欄位,這個欄位用來表示檔案的型別,是檔案,還是管道,還是目錄還是套接字等。d_type 從 Linux 2.6 核心開始就已經支援了,只不過雖然 Linux 核心雖然支援,但有些檔案系統實現了 d_type,而有些,沒有實現,有些是選擇性的實現,也就是需要使用者自己用額外的引數來決定是否開啟d_type的支援。
注意其中的 ftype,1表示支援d_type,0表示不支援。
警告:在沒有d_type支援的XFS上執行Docker,會導致Docker跳過嘗試使用overlay或overlay2驅動程式的階段。現有的版本將繼續執行,但會產生錯誤。這個操作會允許使用者遷移他們的資料。在將來的版本中,這將是一個致命的錯誤,它將阻止Docker啟動。
● 更改儲存驅動程式會使本地系統上現有的容器和映象無法訪問。在更改儲存驅動程式之前,使用docker save儲存已構建的任何映象或將其推送到docker Hub或私有倉庫中,以後便不需要重新建立它們。
配置overlay或者overlay2儲存驅動
如果能使用overlay2
在配置overlay或者overlay2儲存驅動時,請先滿足上一節的先決條件。
下面的步驟將講述如何配置overlay2儲存驅動。如果您需要使用舊版的overlay驅動程式,請指定它。
- 暫停Docker
$ sudo systemctl stop docker
- 複製/var/lib/docker的內容要一個臨時資料夾
$ cp -au /var/lib/docker /var/lib/docker.bk
- 如果要使用與/var/lib/使用的檔案系統不同的備份檔案系統,請格式化該檔案系統並將其裝載到 /var/lib/docker中。確保將此掛載新增到/etc/fstab以使其具有永久性。
- 編輯/etc/sysconfig/docker-storage 檔案。
修改後紅線標註的儲存驅動名稱。目前,我只嘗試過將其從overlay2修改為overlay。
- 啟動Docker
$ sudo systemctl start docker
- 驗證daemon是否在使用overlay。
$ docker info
這是修改之前的資訊:
Docker現在正使用overlay2儲存驅動程式,並自動建立了包含所需lowerdir、upperdir、merged和workdir結構。
這是修改後的資訊:
Overlay2儲存驅動是如何工作的
OverlayFS在一個Linux主機上分層為兩個目錄,並將它們顯示為一個目錄。這些目錄稱為layers
,統一為一個目錄的過程稱為union mount
。OverlayFS
將下層目錄稱為lowerdir
,將上層目錄稱為upperdir
。統一檢視將它們統一為一個目錄,這個過程稱為merged
。overlay2
驅動程式原生支援多達128個較低的OverlayFS層。此功能為與層相關的Docker命令(如docker build
和docker commit
)提供了更好的效能,並且減少了在後臺文件系統上inodes的消耗。
Overlay2如何在磁碟上儲存映象層和容器層
使用命令docker pull ubuntu:18.04
拉取具有三層的ubuntu 18.04映象。
注意:不要直接操作/var/lib/docker/中的任何檔案或目錄。這些檔案和目錄由Docker管理。
在/var/lib/docker/overlay2
資料夾中,我們可以看到四個資料夾。
新的l
(lowercaseL
)目錄包含作為符號連結的縮短層識別符號。這些識別符號用於避免達到mount
命令引數的頁面大小限制。
最底層映象5a54cd...729包含一個link
和一個diff
資料夾。link
儲存的是映象層的id。資料夾diff
包含了映象層的內容。
檢視link
檔案內容:
檢視diff
資料夾內容:
倒數第二層映象和其往上的每一層映象都包含:link
檔案:映象層的id。lower
檔案:表示其依賴的上層映象。以及一個名為diff
的資料夾,包含其映象層的內容。還包含一個merged
資料夾,其中包含上層映象和自身統一的內容,以及一個work
資料夾,供OverlayFS在內部使用。
檢視倒數第二層映象509376...65c的link
檔案和lower
檔案
link
檔案:映象層的ID
lower
檔案:表示其依賴的上層映象
2J60...CONP是最底層映象5a54cd...729的ID,所以表明倒數第二層映象509376...65c是依賴於最底層映象5a54cd...729創立的。
倒數第三層映象d6f68c...49b也是Ubuntu 18.04映象的最頂層映象
檢視倒數第三層映象d6f68c...49b的link
檔案和lower
檔案
link
檔案:映象層的ID
lower
檔案:表示其依賴的上層映象
V27C...NNCB是倒數第二層映象509376...65c的ID,2J60...CONP是最底層映象5a54cd...729的ID。表明倒數第三層映象d6f68c...49b是依賴於倒數第二層映象509376...65c和最底層映象5a54cd...729建立的。映象id出現越早表示映象在越高層,映象id出現越晚表示映象在越底層。
Overlay儲存驅動是怎麼工作的?
此內容僅適用於overlay儲存驅動程式。Docker建議使用overlay2驅動程式,它的工作方式不一樣。
OverlayFS在一個Linux主機上分層兩個目錄,並將它們顯示為一個目錄。這些目錄稱為layers,統一過程稱為union mount。OverlayFS底層的目錄叫做lowerdir
,上層目錄叫做upperdir
。兩個目錄的統一檢視稱為merged
。
下圖展示了Docker映象和容器是如何分層的。映象層就是lowerdir
,容器層就是upperdir
。統一檢視通過名為merged
的目錄公開,該目錄實際上是容器裝載點。該圖顯示了Docker儲存架構如何對映到OverlayFS儲存架構。
當影象層和容器層包含相同的檔案時,容器層會掩蓋影象層中存在相同的檔案,優先顯示容器層的檔案。Overlay
儲存驅動只適用於兩層。這意味著多層映象不能實現為多個OverlayFS層。相反,每個映象層在/var/lib/docker/overlay
下實現為自己的目錄。然後,硬連結被用作為一種節省空間的方式與底層映象共享的資料。使用硬連結會導致過度使用inode,這是overlay
儲存驅動程式的已知限制,並且可能需要額外配置備份檔案系統來解決。
建立容器時,overlay
驅動會將映象頂層目錄與容器的新目錄進行結合。在overlay
中,映象頂層就是lowerdir
,它是隻讀的。容器的新目錄是指upperdir
,它是可讀寫的。
Overlay如何在磁碟上儲存映象層和容器層
使用命令docker pull ubuntu:18.04
拉取具有三層的ubuntu 18.04映象。映象層的ID與目錄的ID不對應。
映象層
每個映象層在/var/lib/docker/overlay/中都有自己的目錄,如下所示。
overlay的每一個映象層都有一個完整的目錄結構,映象與映象之間通過硬連結共享檔案。映象層目錄包含該層特有的檔案以及與較低層共享的資料的硬連結。這樣可以有效地利用磁碟空間。
檢視1768...5cb映象層和4273..c5c6映象層通過硬連結共享的檔案:
可以看到1768...5cb映象層和4273..c5c6映象層的ls命令檔案都有相同的inode號,表明它們是通過硬連結共享的。
(一般情況下,檔名和inode號碼是"一一對應"關係,每個inode號碼對應一個檔名。但是,Unix/Linux系統允許,多個檔名指向同一個inode號碼。這意味著,可以用不同的檔名訪問同樣的內容;對檔案內容進行修改,會影響到所有檔名;但是,刪除一個檔名,不影響另一個檔名的訪問。這種情況就被稱為"硬連結"(hard link)。)
容器層
容器層也存在於磁碟上Docker主機的檔案系統的/var/lib/Docker/overlay下。
執行一個ubuntu18.04映象。
新增加的兩個資料夾是容器層,5c7a...b0a-init是容器初始層。
檢視5c7a...b0a層的內容:
5c7a...b0a容器層包含三個資料夾和一個檔案。lower-id
檔案包含容器基於映象的頂層id,即OverlayFS的lowerdir
。
檢視5c7a...b0a容器層的lower-id
:
5c7a...b0a容器層的lower-id
正好是映象層lowerdir
的ID。
檢視5c7a...b0a容器層的ls命令檔案:
跟前面的1768...5cb映象層和4273..c5c6映象層的ls命令檔案都有相同的inode號,這表明每次新建立容器時都會建立大量的硬連結,消耗大量的inode。在Linux系統中,inode的數量即硬連結的數量是有限的,達到一定數量後將無法再建立新的容器。這是使用overlay儲存驅動的一個缺點。
upper
目錄包含容器讀寫層的內容,它對應於OverlayFS的upperdir
。
merged
目錄是lowerdir
和upperdir
的聯合掛載,它是執行容器中的檔案系統檢視。
work
目錄是OverlayFS的內部目錄。
容器是如何使用overlay或者overlay2進行讀寫的?
讀取檔案
考慮三種情況,容器使用overlay驅動開啟一個檔案進行讀取訪問。
●檔案不存在於容器層:如果容器開啟或者讀取一個檔案,這個檔案不存在於容器層(upper
目錄),容器將從映象層(lowerdir
目錄)讀取該檔案。這會產生很小的效能開銷。
●檔案只存在於容器層:如果容器開啟或者讀取一個檔案,這個檔案存只在於容器層(upper
目錄),不存在於映象層(lowerdir
目錄),容器會直接從容器層中讀取該檔案。
●檔案在容器層和映象層中都存在:如果容器開啟或者讀取一個檔案,這個檔案在容器層和映象層中都存在,容器將會讀取容器層中的檔案。容器層(upper
目錄)中的檔案會模糊映象層(lowerdir
目錄)中的同名檔案。
修改檔案或資料夾
考慮如下場景,當容器中的檔案被修改時。
●第一次寫檔案:容器第一次寫入存在於映象層(lowerdir
目錄),不存在於容器層(upper
目錄)的檔案。overlay
或者overlay2
驅動會執行copy_up操作,將檔案從映象層(lowerdir
目錄)拷貝到容器層(upper
目錄)。容器會將更改寫入容器層中檔案的新副本。但是,OverlayFS是在檔案級別,而不是塊級別上工作的。這意味著所有OverlayFS的copy_up操作都將複製整個檔案,即使該檔案非常大但只有一小部分被修改。這會對容器寫入效能產生顯著影響。然而,有兩點值得注意:
○copy_up操作只在第一次寫入給定檔案時發生。對同一檔案的後續寫入操作是針對已複製到容器的檔案副本。
○ OverlayFS僅適用於兩層。這意味著效能應該比AUFS好,AUFS在搜尋具有多個層的映象中的檔案時,AUFS可能會有明顯的延遲。這項優勢應用於overlay
和overlay2
驅動。overlayfs2
在初始讀取時,效能會略低於overlayfs
。因為overlayfs2
必須遍歷更多層,但它會快取結果,因此這只是一個很小的損失。
●刪除檔案和資料夾:
○ 當在容器中刪除檔案時,容器層(upperdir目錄)中會建立一個 whiteout檔案(空白檔案)。映象層(lowerdir
目錄)中的檔案不會被刪除,因為映象層(lowerdir
目錄)是隻讀的。但是,whiteout檔案(空白檔案)將阻止容器使用它。
○ 當在容器中刪除資料夾時,容器層(upperdir目錄)中會建立一個opaque資料夾(不透明資料夾)。這與whiteout檔案的工作方式相同,可以有效地防止目錄被訪問,即使它仍然存在於映象層(lowerdir
目錄)。
●修改目錄名稱:只有當源路徑和目標路徑都在頂層時,才允許對目錄呼叫rename(2)
。否則,會返回EXDEV
錯誤(“不允許跨裝置連結”)。我們的程式需要設計處理EXDEV
錯誤的功能,並回退到”copy and unlikn“策略。
OverlayFS和Docker的效能
overlay2
和overlay
的效能都要比aufs
和devicemapper
好。在某些特定的場景中,overlay2
的效能要比btrfs
好。然後,我們需要明白如下細節:
●頁快取。OverlayFS支援頁快取共享。訪問同一檔案的多個容器共享該檔案的單個頁快取項。這使得overlay2
和overlay
驅動具有高效的記憶體使用效率,並且是PaaS等高密度用例的好選擇。
●copy_up。與AUFS一樣,OverlayFS在容器第一次寫入檔案時執行copy_up操作。這會增加寫入操作的延遲,特別是對於大檔案。但是,一旦檔案被複制,對該檔案的所有後續寫入都發生在容器層(upper
目錄),而不需要進一步的複製操作。
OverlayFS的copy_up操作比AUFS的copy_up操作更快。因為AUFS支援的層比OverlayFS多,在眾多的AUFS層中搜索檔案可能會造成比較大的延遲。overlay2
同樣支援多層,但是overlay2
通過快取技術減輕了多層搜尋對效能的影響。
●Inode限制。使用overlay
驅動可能會消耗大量的innode。當主機上存在大量映象和容器時,這種情況會更加嚴重。增加檔案系統可用inode數量的唯一方法是重新格式化它。為了避免出現這個問題,強烈推薦使用overlay2
驅動。
效能的最佳實踐
以下通用效能最佳實踐也適用於OverlayFS。
●使用更快的儲存介質:固態硬碟(SSDs)比傳統的磁碟具有更快的讀寫速度。
●對於寫操作繁重的工作負載,使用volumes:Volumes為寫操作繁重的工作負載提供了最佳的效能。這是因為volumes繞過了儲存驅動程式,並且不會產生thin provisioning和copy-on-write帶來的任何潛在開銷。volumes還有其他好處,比如允許我們在容器之間共享資料,並會持久化儲存資料即使沒有容器使用這些資料。
OverlayFS相容性的限制
下面概述OverlayFS與其他檔案系統不相容的方面:
●open(2):OverlayFS只是實現了POSIX標準的一個子集。這可能導致某些OverlayFS操作違反POSIX標準。其中一種操作是copy_up操作。我們的程式在執行操作fd1=open("foo", O_RDONLY)
和fd2=open("foo", O_RDWR)
。在這種情況下,我們程式期望的是fd1
和fd2
指向的是同一個檔案。但是,由於在第二次呼叫open(2)
之後發生copy_up操作,檔案描述符引用了不同的檔案。fd1
繼續引用映象層(lowerdir
目錄)中的檔案,而fd2
則引用容器層(upperdir目錄)中的檔案。一種解決方法是touch導致copy_up操作發生的檔案。所有後續的open(2)
操作,無論是隻讀還是讀寫訪問模式,都會引用容器層(upperdir目錄)中的檔案。
據悉,yum
會受到影響,除非安裝了yum-plugin-ov1
軟體包。如果yum-plugin-ov1
軟體包我們的系統中(比如RHEL/CentOS 6.8之前的版本,或者7.2)不支援,我們可能需要在執行yum install
之前執行touch /var/lib/rpm/*
。yum-plugin-ov1
軟體包實現了上面針對yum
的touch
操作。
●rename(2):OverlayFS並沒有完成支援rename(2)
系統呼叫。我們的程式需要檢測這個失敗,並且回退到“copy and unlink”策略。
參考文章
[1] Use the OverlayFS storage driver,https://docs.docker.com/storage/storagedriver/overlayfs-driver/
[2] overlay和overlay2的區別,https://www.cnblogs.com/elnino/p/11015076.html
轉自:知乎使用者吳小正的文章