容器如何工作:OverlayFS

Julia Evans發表於2019-11-23

今天早上,我為未來潛在容器雜誌畫了一幅 OverlayFS 的漫畫,我對這個主題感到興奮,想寫一篇關於它的部落格來提供更多詳細資訊。

容器映象很大

容器映象可能會很大(儘管有些很小,例如 alpine linux 才 2.5MB)。Ubuntu 16.04 約為 27 MB,Anaconda Python 發行版為 800MB 至 1.5GB

你以映象啟動的每個容器都是原始空白狀態,彷彿它只是為使用容器而複製的一份映象複製一樣。但是對於大的容器映象,像 800MB 的 Anaconda 映象,複製一份複製既浪費磁碟空間也很慢。因此 Docker 不會複製,而是採用疊加

疊加如何工作

OverlayFS,也被稱為 聯合檔案系統聯合掛載,它可讓你使用 2 個目錄掛載檔案系統:“下層”目錄和“上層”目錄。

基本上:

  • 檔案系統的下層目錄是隻讀的
  • 檔案系統的上層目錄可以讀寫

當程序“讀取”檔案時,OverlayFS 檔案系統驅動將在上層目錄中查詢並從該目錄中讀取檔案(如果存在)。否則,它將在下層目錄中查詢。

當程序“寫入”檔案時,OverlayFS 會將其寫入上層目錄。

讓我們使用 mount 製造一個疊加層!

這有點抽象,所以讓我們製作一個 OverlayFS 並嘗試一下!這將只包含一些檔案:我將建立上、下層目錄,以及用來掛載合併的檔案系統的 merged 目錄:

$ mkdir upper lower merged work
$ echo "I'm from lower!" > lower/in_lower.txt
$ echo "I'm from upper!" > upper/in_upper.txt
$ # `in_both` is in both directories
$ echo "I'm from lower!" > lower/in_both.txt
$ echo "I'm from upper!" > upper/in_both.txt

合併上層目錄和下層目錄非常容易:我們可以透過 mount 來完成!

$ sudo mount -t overlay overlay
    -o lowerdir=/home/bork/test/lower,upperdir=/home/bork/test/upper,workdir=/home/bork/test/work
    /home/bork/test/merged

在執行此操作時,我不斷收到一條非常煩人的錯誤訊息,內容為:mount: /home/bork/test/merged: special device overlay does not exist.。這條訊息是錯誤的,實際上只是意味著我指定的一個目錄缺失(我寫成了 ~/test/merged,但它沒有被展開)。

讓我們嘗試從 OverlayFS 中讀取其中一個檔案!檔案 in_both.txt 同時存在於 lower/upper/ 中,因此應從 upper/ 目錄中讀取該檔案。

$ cat merged/in_both.txt
"I'm from upper!

可以成功!

目錄的內容就是我們所期望的:

find lower/ upper/ merged/
lower/
lower/in_lower.txt
lower/in_both.txt
upper/
upper/in_upper.txt
upper/in_both.txt
merged/
merged/in_lower.txt
merged/in_both.txt
merged/in_upper.txt

建立新檔案時會發生什麼?

$ echo 'new file' > merged/new_file
$ ls -l */new_file
-rw-r--r-- 1 bork bork 9 Nov 18 14:24 merged/new_file
-rw-r--r-- 1 bork bork 9 Nov 18 14:24 upper/new_file

這是有作用的,新檔案會在 upper 目錄建立。

刪除檔案時會發生什麼?

讀寫似乎很簡單。但是刪除會發生什麼?開始試試!

$ rm merged/in_both.txt

發生了什麼?讓我們用 ls 看下:

ls -l upper/in_both.txt  lower/lower1.txt  merged/lower1.txt
ls: cannot access 'merged/in_both.txt': No such file or directory
-rw-r--r-- 1 bork bork    6 Nov 18 14:09 lower/in_both.txt
c--------- 1 root root 0, 0 Nov 18 14:19 upper/in_both.txt

所以:

  • in_both.txt 仍在 lower 目錄中,並且保持不變
  • 它不在 merged 目錄中。到目前為止,這就是我們所期望的。
  • 但是在 upper 中發生的事情有點奇怪:有一個名為 upper/in_both.txt 的檔案,但是它是字元裝置?我想這就是 overlayfs 驅動表示刪除的檔案的方式。

如果我們嘗試複製這個奇怪的字元裝置檔案,會發生什麼?

$ sudo cp upper/in_both.txt upper/in_lower.txt
cp: cannot open 'upper/in_both.txt' for reading: No such device or address

好吧,這似乎很合理,複製這個奇怪的刪除訊號檔案並沒有任何意義。

你可以掛載多個“下層”目錄

Docker 映象通常由 25 個“層”組成。OverlayFS 支援具有多個下層目錄,因此你可以執行:

mount -t overlay overlay
      -o lowerdir:/dir1:/dir2:/dir3:...:/dir25,upperdir=...

因此,我假設這是有多個 Docker 層的容器的工作方式,它只是將每個層解壓縮到一個單獨的目錄中,然後要求 OverlayFS 將它們全部合併在一起,並使用一個空的上層目錄,容器將對其進行更改。

Docker 也可以使用 btrfs 快照

現在,我使用的是 ext4,而 Docker 使用 OverlayFS 快照來執行容器。但是我曾經用過 btrfs,接著 Docker 將改為使用 btrfs 的寫時複製快照。(這是 Docker 何時使用哪種儲存驅動的列表)

以這種方式使用 btrfs 快照會產生一些有趣的結果:去年某個時候,我在筆記本上執行了數百個臨時的 Docker 容器,這導致我用盡了 btrfs 後設資料空間(像這個人一樣)。這真的很令人困惑,因為我以前從未聽說過 btrfs 後設資料,而且弄清楚如何清理檔案系統以便再次執行 Docker 容器非常棘手。(這個 docker github 上的提案描述了 Docker 和 btrfs 的類似問題)

以簡單的方式嘗試容器功能很有趣!

我認為容器通常看起來像是在做“複雜的”事情,我認為將它們分解成這樣很有趣。你可以執行一條 mount 咒語,而實際上並沒有做任何與容器相關的其他事情,看看疊加層是如何工作的!


via: https://jvns.ca/blog/2019/11/18/how-containers-work–overlayfs/

作者:Julia Evans 選題:lujun9972 譯者:geekpi 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出

相關文章