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
儲存空間驅動程式。
停止 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/docker/daemon.json
。 如果它尚不存在,請建立它。 假設檔案是空的,請新增以下內容。{ "storage-driver": "overlay2" }
如果
daemon.json
檔案包含無效的 JSON,Docker 將不會啟動。啟動 Docker。
$ sudo systemctl start docker
驗證守護程式是否正在使用
overlay2
儲存空間驅動程式。 使用docker info
命令並尋找儲存空間驅動程式
和支援檔案系統
。$ docker info Containers: 0 Images: 0 Storage Driver: overlay2 Backing Filesystem: xfs Supports d_type: true Native Overlay Diff: true <...>
Docker 現在正在使用 overlay2
儲存空間驅動程式,並且已使用所需的 lowerdir
、upperdir
、merged
和 workdir
建構自動建立覆蓋掛載。
繼續閱讀以瞭解 OverlayFS 在 Docker 容器中如何運作的詳細資訊,以及效能建議和其與不同支援檔案系統相容性的限制相關資訊。
overlay2
驅動程式的運作方式
OverlayFS 在單個 Linux 主機上將兩個目錄層疊,並將它們呈現為單個目錄。這些目錄稱為「層」,而統一過程稱為「聯合成掛載」。OverlayFS 將下層目錄稱為 lowerdir
,將上層目錄稱為 upperdir
。統一視圖通過其自身的目錄(稱為 merged
)公開。
overlay2
驅動程式原生支援最多 128 個 OverlayFS 下層。此功能為與層相關的 Docker 命令(例如 docker build
和 docker 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
目錄,其中包含其父層及其自身的統一內容,以及一個 work
目錄,供 OverlayFS 內部使用。
$ 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
要查看使用 Docker 的 overlay
儲存驅動程式時存在的掛載,請使用 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
的目錄公開,該目錄實際上是容器的掛載點。


如果映像檔層和容器層包含相同的檔案,則容器層 (upperdir
) 優先,並遮蔽映像檔層中相同檔案的存在。
要建立容器,overlay2
驅動程式會將表示映像檔頂層的目錄與容器的新目錄組合在一起。映像檔的層是覆蓋中的 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
目錄是 lowerdir
和 upperdirs
的聯合成掛載,它構成了從正在執行的容器內部看到的檔案系統視圖。
work
目錄是 OverlayFS 內部的。
要查看使用 Docker 的 overlay2
儲存驅動程式時存在的掛載,請使用 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
) 中建立一個_白化_檔案。映像檔層 (lowerdir
) 中的檔案版本不會被刪除(因為lowerdir
是唯讀的)。但是,白化檔案會阻止容器使用它。當在容器中刪除_目錄_時,會在容器 (
upperdir
) 中建立一個_不透明目錄_。這與白化檔案的工作方式相同,可以有效地阻止存取該目錄,即使它仍然存在於映像檔 (lowerdir
) 中。
重新命名目錄
僅當來源和目標路徑都在頂層時,才允許對目錄呼叫 rename(2)
。否則,它會傳回 EXDEV
錯誤(「不允許跨裝置連結」)。您的應用程式需要設計為處理 EXDEV
並使用「複製和取消連結」策略。
OverlayFS 和 Docker 效能
overlay2
的效能可能比 btrfs
好。但是,請注意以下細節
頁面快取
OverlayFS 支援頁面快取共享。多個存取相同檔案的容器共享該檔案的單個頁面快取項目。這使得 overlay2
驅動程式可以有效地利用記憶體,並且是高密度使用案例(例如 PaaS)的良好選擇。
複製
與其他寫入時複製檔案系統一樣,每當容器第一次寫入檔案時,OverlayFS 就會執行複製作業。這可能會增加寫入作業的延遲,尤其是對於大型檔案。但是,一旦檔案被複製,後續對該檔案的所有寫入操作都將在上層進行,而無需進一步的複製操作。
效能最佳實務
以下一般效能最佳實務適用於 OverlayFS。
使用快速儲存裝置
固態硬碟 (SSD) 提供比旋轉磁碟更快的讀取和寫入速度。
將磁碟區用於寫入密集型工作負載
磁碟區為寫入密集型工作負載提供最佳且最可預測的效能。這是因為它們繞過了儲存驅動程式,並且不會產生由精簡配置和寫入時複製引入的任何潛在開銷。磁碟區還有其他好處,例如允許您在容器之間共享資料,並在沒有正在執行的容器使用它們時仍保留您的資料。
OverlayFS 相容性的限制
總結 OverlayFS 與其他檔案系統不相容的方面
open(2)
- OverlayFS 僅實作 POSIX 標準的一個子集。這可能導致某些 OverlayFS 作業違反 POSIX 標準。其中一個作業就是複製作業。假設您的應用程式呼叫
fd1=open("foo", O_RDONLY)
,然後呼叫fd2=open("foo", O_RDWR)
。在這種情況下,您的應用程式預期fd1
和fd2
指的是同一個檔案。但是,由於在第二次呼叫open(2)
之後發生的複製操作,描述符指的是不同的檔案。fd1
繼續參考映像檔 (lowerdir
) 中的檔案,而fd2
參考容器 (upperdir
) 中的檔案。解決此問題的方法是touch
檔案,這會導致複製操作發生。後續所有open(2)
作業,無論是唯讀還是讀寫存取模式,都參考容器 (upperdir
) 中的檔案。已知
yum
會受到影響,除非安裝了yum-plugin-ovl
套件。如果您的發行版本(例如 6.8 或 7.2 之前的 RHEL/CentOS)中沒有yum-plugin-ovl
套件,您可能需要在執行yum install
之前執行touch /var/lib/rpm/*
。此套件為yum
實作了上面提到的touch
解決方法。 rename(2)
- OverlayFS 不完全支援
rename(2)
系統呼叫。您的應用程式需要偵測其失敗並使用「複製和取消連結」策略。