使用 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
命令並查詢Storage Driver
和Backing filesystem
。$ 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
要檢視在將 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
的目錄公開,該目錄實際上是容器的掛載點。


如果映象層和容器層包含相同的檔案,則容器層 (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,該 ID 是 OverlayFS 的 lowerdir
。
$ cat /var/lib/docker/overlay2/ec444863a55a9f1ca2df72223d459c5d940a721b2288ff86a3f27be28b53be6c/lower-id
55f1e14c361b90570df46371b20ce6d480c434981cbda5fd68c6ff61aa0a5358
upper
目錄包含容器的讀寫層的目錄,該目錄對應於 OverlayFS 的 upperdir
。
merged
目錄是 lowerdir
和 upperdirs
的聯合掛載,它包含從執行的容器內看到的檔案系統的檢視。
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
如何處理容器讀寫操作
讀取檔案
考慮三個場景,在這些場景中,容器使用覆蓋開啟檔案以進行讀取訪問。
容器層中不存在該檔案
如果容器以讀取訪問方式開啟檔案,並且該檔案尚不存在於容器 (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 等高密度用例的理想選擇。
Copyup
與其他寫時複製檔案系統一樣,每當容器首次寫入檔案時,OverlayFS 都會執行 copy-up 操作。這可能會在寫入操作中增加延遲,尤其是對於大型檔案。但是,一旦檔案被複制,所有後續對該檔案的寫入都會發生在上層,而無需進一步的 copy-up 操作。
效能最佳實踐
以下通用效能最佳實踐適用於 OverlayFS。
使用快速儲存
固態硬碟 (SSD) 提供比旋轉磁碟更快的讀寫速度。
對寫入密集型工作負載使用卷
卷為寫入密集型工作負載提供了最佳和最可預測的效能。這是因為它們繞過儲存驅動程式,並且不會產生由精簡配置和寫時複製引入的任何潛在開銷。卷還有其他優點,例如允許您在容器之間共享資料,並且即使沒有執行的容器使用它們,也能持久化您的資料。
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-ovl
包。如果在 6.8 或 7.2 之前的 RHEL/CentOS 等發行版中,yum-plugin-ovl
包不可用,您可能需要在執行yum install
之前執行touch /var/lib/rpm/*
。該包實現了上述針對yum
的touch
解決方案。 rename(2)
- OverlayFS 不完全支援
rename(2)
系統呼叫。您的應用程式需要檢測其失敗並回退到“複製和取消連結”策略。