OverlayFS 儲存驅動程式

OverlayFS 是一種聯合檔案系統。

此頁面將 Linux 核心驅動程式稱為 OverlayFS,將 Docker 儲存驅動程式稱為 overlay2

注意

有關 fuse-overlayfs 驅動程式的資訊,請查閱無根模式文件

先決條件

OverlayFS 是建議的儲存驅動程式,若您符合以下先決條件則支援使用

  • Linux 核心版本 4.0 或更高版本,或使用核心版本 3.10.0-514 或更高版本的 RHEL 或 CentOS。

  • overlay2 驅動程式支援 xfs 後端檔案系統,但僅限於啟用 d_type=true 的情況。

    使用 xfs_info 驗證 ftype 選項是否設定為 1。要正確格式化 xfs 檔案系統,請使用 -n ftype=1 標誌。

  • 變更儲存驅動程式會導致本機系統上現有的容器和映像檔無法存取。在變更儲存驅動程式之前,請使用 docker save 儲存任何您已建置的映像檔,或將它們推送到 Docker Hub 或私有註冊表,這樣您就不必稍後重新建立它們。

使用 overlay2 儲存驅動程式配置 Docker

在執行此程序之前,您必須先滿足所有先決條件

以下步驟說明如何配置 overlay2 儲存驅動程式。

  1. 停止 Docker。

    $ sudo systemctl stop docker
    
  2. /var/lib/docker 的內容複製到臨時位置。

    $ cp -au /var/lib/docker /var/lib/docker.bk
    
  3. 如果您想使用與 /var/lib/ 所用的檔案系統不同的後端檔案系統,請格式化該檔案系統並將其掛載到 /var/lib/docker。務必將此掛載新增到 /etc/fstab 以使其永久生效。

  4. 編輯 /etc/docker/daemon.json。如果該檔案尚不存在,請建立它。假設該檔案為空,請新增以下內容。

    {
      "storage-driver": "overlay2"
    }

    如果 daemon.json 檔案包含無效的 JSON,Docker 將不會啟動。

  5. 啟動 Docker。

    $ sudo systemctl start docker
    
  6. 驗證守護程式正在使用 overlay2 儲存驅動程式。使用 docker info 指令並查找 Storage DriverBacking filesystem

    $ docker info
    
    Containers: 0
    Images: 0
    Storage Driver: overlay2
     Backing Filesystem: xfs
     Supports d_type: true
     Native Overlay Diff: true
    <...>
    

Docker 現在正在使用 overlay2 儲存驅動程式,並已自動建立帶有所需 lowerdirupperdirmergedworkdir 結構的 overlay 掛載點。

請繼續閱讀,以了解 OverlayFS 在 Docker 容器中如何運作的詳細資訊,以及效能建議和其與不同後端檔案系統相容性限制的資訊。

overlay2 驅動程式的運作方式

OverlayFS 在單一 Linux 主機上疊加兩個目錄,並將它們呈現為單一目錄。這些目錄稱為層 (layers),統一過程稱為聯合掛載 (union mount)。OverlayFS 將下層目錄稱為 lowerdir,將上層目錄稱為 upperdir。統一視圖透過其自己的目錄 merged 暴露。

overlay2 驅動程式原生支援最多 128 個下層 OverlayFS 層。此功能為與層相關的 Docker 指令(例如 docker builddocker commit)提供更好的效能,並在後端檔案系統上消耗更少的 inode。

映像檔與容器層級在磁碟上的儲存方式

使用 docker pull ubuntu 下載一個五層映像檔後,您可以在 /var/lib/docker/overlay2 下看到六個目錄。

警告

請勿直接操作 /var/lib/docker/ 中的任何檔案或目錄。這些檔案和目錄由 Docker 管理。

$ 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 (小寫 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 目錄,其中包含其父層和自身的統一內容,以及一個由 OverlayFS 內部使用的 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

要查看使用 overlay 儲存驅動程式與 Docker 時存在的掛載點,請使用 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)

第二行中的 rw 表示 overlay 掛載點是可讀寫的。

下圖顯示 Docker 映像檔和 Docker 容器是如何分層的。映像層是 lowerdir,容器層是 upperdir。如果映像檔有多個層,則會使用多個 lowerdir 目錄。統一視圖透過一個名為 merged 的目錄暴露,該目錄實際上是容器的掛載點。

How Docker constructs map to OverlayFS constructs

當映像層和容器層包含相同的檔案時,容器層 (upperdir) 優先,並隱藏映像層中相同檔案的存在。

要建立一個容器,overlay2 驅動程式會將代表映像檔頂層的目錄與容器的新目錄結合。映像檔的層是 overlay 中的 lowerdirs,並且是唯讀的。容器的新目錄是 upperdir,並且是可寫的。

映像檔與容器層級在磁碟上的儲存方式

以下 docker pull 指令顯示 Docker 主機正在下載一個包含五個層的 Docker 映像檔。

$ 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

映像層

每個映像層在 /var/lib/docker/overlay/ 中都有自己的目錄,其中包含其內容,如下例所示。映像層 ID 不對應於目錄 ID。

警告

請勿直接操作 /var/lib/docker/ 中的任何檔案或目錄。這些檔案和目錄由 Docker 管理。

$ 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

映像層目錄包含該層特有的檔案,以及與下層共用資料的硬連結。這有助於高效利用磁碟空間。

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

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

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

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

容器層

容器也存在於 Docker 主機檔案系統中的 /var/lib/docker/overlay/ 下。如果您使用 ls -l 指令列出正在執行容器的子目錄,會發現存在三個目錄和一個檔案

$ ls -l /var/lib/docker/overlay2/<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

lower-id 檔案包含容器所基於的映像檔頂層 ID,即 OverlayFS 的 lowerdir

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

55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358

upper 目錄包含容器讀寫層的內容,對應於 OverlayFS 的 upperdir

merged 目錄是 lowerdirupperdirs 的聯合掛載點,它構成了運行中容器內部的檔案系統視圖。

work 目錄是 OverlayFS 內部使用的。

要查看使用 overlay2 儲存驅動程式與 Docker 時存在的掛載點,請使用 mount 指令。以下輸出為了可讀性已截斷。

$ mount | grep overlay

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

第二行中的 rw 表示 overlay 掛載點是可讀寫的。

容器讀寫操作如何與 overlay2 協同運作

讀取檔案

考慮容器使用 overlay 開啟檔案進行讀取存取的三種情況。

檔案不存在於容器層中

如果容器開啟檔案進行讀取存取,且該檔案尚不存在於容器中 (upperdir),則會從映像檔 (lowerdir) 讀取。這會帶來非常小的效能開銷。

檔案僅存在於容器層中

如果容器開啟檔案進行讀取存取,且該檔案存在於容器中 (upperdir) 但不存在於映像檔中 (lowerdir),則直接從容器讀取。

檔案同時存在於容器層和映像層中

如果容器開啟檔案進行讀取存取,且該檔案存在於映像層和容器層中,則讀取容器層中的檔案版本。容器層中的檔案 (upperdir) 會隱藏映像層中同名的檔案 (lowerdir)。

修改檔案或目錄

考慮容器中檔案被修改的一些情況。

首次寫入檔案

容器首次寫入現有檔案時,該檔案不存在於容器中 (upperdir)。overlay2 驅動程式會執行 copy_up 操作,將檔案從映像檔 (lowerdir) 複製到容器 (upperdir)。然後,容器將變更寫入容器層中檔案的新副本。

然而,OverlayFS 是在檔案層級而不是區塊層級運作。這表示所有 OverlayFS 的 copy_up 操作都會複製整個檔案,即使檔案很大且只修改了其中一小部分。這可能會對容器寫入效能產生顯著影響。然而,有兩點值得注意

  • copy_up 操作僅在首次寫入給定檔案時發生。後續對同一檔案的寫入會針對已複製到容器的檔案副本進行。

  • OverlayFS 支援多層運作。這表示在具有多層的映像檔中搜尋檔案時,效能可能會受到影響。

刪除檔案和目錄

  • 當容器內刪除一個*檔案*時,會在容器中 (upperdir) 建立一個*白影 (whiteout)* 檔案。映像層中 (lowerdir) 的檔案版本並未刪除(因為 lowerdir 是唯讀的)。然而,白影檔案會阻止該檔案對容器可用。

  • 當容器內刪除一個*目錄*時,會在容器中 (upperdir) 建立一個*不透明目錄 (opaque directory)*。這與白影檔案的運作方式相同,有效地阻止該目錄被存取,即使它仍然存在於映像檔中 (lowerdir)。

重新命名目錄

僅當來源和目標路徑都在頂層時,才允許對目錄呼叫 rename(2)。否則,它會回傳 EXDEV 錯誤(「不允許跨裝置連結」)。您的應用程式需要設計為處理 EXDEV 並回退到「複製並解除連結」策略。

OverlayFS 與 Docker 效能

overlay2 的效能可能優於 btrfs。然而,請注意以下細節

頁面快取

OverlayFS 支援頁面快取共用。多個容器存取同一個檔案時,會共用該檔案的單一頁面快取條目。這使得 overlay2 驅動程式在記憶體使用上效率高,並且是 PaaS 等高密度使用案例的良好選擇。

向上複製 (Copyup)

與其他寫入時複製檔案系統一樣,每當容器首次寫入檔案時,OverlayFS 都會執行向上複製操作。這可能會增加寫入操作的延遲,尤其是對於大型檔案。然而,一旦檔案被複製上去,所有後續對該檔案的寫入都會發生在上層,而無需進一步的向上複製操作。

效能最佳實務

以下通用效能最佳實踐適用於 OverlayFS。

使用快速儲存

固態硬碟 (SSD) 提供比傳統硬碟更快的讀寫速度。

對寫入密集型工作負載使用卷 (volumes)

對於寫入密集型工作負載,卷 (volumes) 提供最佳且最可預測的效能。這是因為它們繞過了儲存驅動程式,並且不會產生精簡配置 (thin provisioning) 和寫入時複製 (copy-on-write) 所引入的任何潛在開銷。卷還有其他好處,例如允許您在容器之間共用資料,以及即使沒有運行中的容器使用它們也能持久化您的資料。

OverlayFS 相容性限制

總結 OverlayFS 與其他檔案系統不相容的方面

open(2)
OverlayFS 僅實作 POSIX 標準的一個子集。這可能導致某些 OverlayFS 操作違反 POSIX 標準。其中一個操作就是向上複製 (copy-up)。假設您的應用程式呼叫 fd1=open("foo", O_RDONLY),然後再呼叫 fd2=open("foo", O_RDWR)。在這種情況下,您的應用程式預期 fd1fd2 指向同一個檔案。然而,由於在第二次呼叫 open(2) 後發生了向上複製操作,這些描述符會指向不同的檔案。fd1 繼續引用映像檔中 (lowerdir) 的檔案,而 fd2 引用容器中 (upperdir) 的檔案。解決此問題的方法是 touch 檔案,這會導致向上複製操作發生。所有後續的 open(2) 操作,無論是唯讀還是讀寫存取模式,都會引用容器中 (upperdir) 的檔案。

已知 yum 會受到影響,除非安裝了 yum-plugin-ovl 套件。如果您的發行版中沒有 yum-plugin-ovl 套件(例如 RHEL/CentOS 6.8 或 7.2 之前的版本),您可能需要在執行 yum install 之前執行 touch /var/lib/rpm/*。此套件為 yum 實作了上述的 touch 解決方案。

rename(2)
OverlayFS 不完全支援 rename(2) 系統呼叫。您的應用程式需要檢測其失敗並回退到「複製並解除連結」策略。
© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.