容器儲存和容器儲存介面(CSI)在容器化環境中扮演著截然不同的角色。容器儲存專注於管理容器映像檔,確保它們在需要時可以被容器引擎取用。而 CSI 則負責提供容器執行時所需的持久化儲存,例如資料函式庫或應用程式產生的檔案。本文將聚焦於容器儲存,特別是 Podman 使用的 containers/storage 專案。這個專案讓開發者和系統管理員可以直接操作容器儲存,不再受限於 Docker daemon 的間接控制。透過 /etc/containers/storage.conf 檔案,我們可以設定儲存驅動程式等關鍵選項,進而影響容器與底層儲存的互動方式。目前支援的儲存驅動程式包括 overlay、vfs、devmapper、aufs、btrfs 和 zfs,這些驅動程式通常以圖形結構管理容器映像檔的層級關係。在 Fedora 34 或更新版本中,Podman 預設使用 overlay 驅動程式,實際上是 overlay 檔案系統的版本 2。OverlayFS 是一種聯合檔案系統,它透過覆寫目錄樹的方式,僅儲存差異,有效節省儲存空間。

在容器環境中,OverlayFS 以唯讀層為基礎,逐層疊加,直到執行中的容器建立一個讀寫層作為根檔案系統。以下將透過一個實際案例,展示 Podman 下載容器映像檔的過程。首先,執行 podman pull quay.io/centos7/httpd-24-centos7:latest 下載映像檔。接著,使用 podman info | grep -A19 "store:" 命令檢視 Podman 的儲存組態,找到 graphRoot 目錄,這個目錄存放了容器映像檔的層級結構。預設情況下,graphRoot 目錄是 /var/lib/containers/storage,無根容器的對應路徑為 $HOME/.local/share/containers/storage。進入 graphRoot 目錄,執行 ls 命令,可以看到 overlayoverlay-containersoverlay-imagesoverlay-layers 等目錄,這些目錄存放了容器映像檔的不同層級和相關資訊。透過觀察這些目錄的結構和內容,可以更深入地理解 Podman 容器儲存的運作機制。

容器儲存技術:原理、組態與實戰應用

在探討實際範例與應用情境之前,我們首先需要理解容器儲存(Container Storage)與容器儲存介面(Container Storage Interface, CSI)之間的主要差異。這兩者在容器技術堆疊中扮演著不同的角色。

容器儲存,過去常被稱為底層容器儲存,主要負責處理容器映像檔在 Copy-on-Write (COW) 檔案系統上的儲存。容器映像檔需要在不同的環境之間傳輸,直到容器引擎指示執行它們。因此,我們需要一種方式來儲存這些映像檔,直到它們被實際使用。這就是容器儲存的職責。

另一方面,當我們開始使用 Kubernetes 等容器協調工具時,CSI 則負責提供容器執行時寫入資料所需的區塊或檔案儲存。簡單來說,容器儲存負責存放「程式」,CSI 負責存放「資料」。

接下來,我們將重點關注容器儲存及其組態。稍後,我們將討論容器的外部儲存,以及在 Podman 中將主機本機儲存暴露給執行中容器的各種方法。

容器儲存的創新:containers/storage 專案

Podman 的一項重大創新是 containers/storage 專案(https://github.com/containers/storage)。這個專案提供了一種在主機上存取容器儲存的通用方法。在使用 Docker 的早期,我們必須透過 Docker daemon 才能與容器儲存互動。Docker daemon 將底層儲存隱藏起來,使得使用者和系統管理員無法直接存取。

透過 containers/storage 專案,我們現在可以使用多種工具來分析、管理或操作容器儲存。例如,我曾經在一個專案中需要同時使用多個工具來監控容器映像檔的空間使用情況,containers/storage 專案讓我能夠輕鬆地整合這些工具,而無需擔心底層儲存的相容性問題。

這個底層軟體的組態對於 Podman 及其相關工具至關重要。我們可以透過 /etc/containers/storage.conf 檔案來檢視或編輯其組態。

觀察這個組態檔案,我們可以發現,可以修改許多選項,以調整容器與底層儲存的互動方式。其中,最重要的選項之一就是儲存驅動程式。

儲存驅動程式:選擇 COW 驅動程式

組態檔案提供了一個選擇預設 Copy On Write (COW) 容器儲存驅動程式的選項。在撰寫本文時,目前的版本支援以下 COW 驅動程式:

  • overlay
  • vfs
  • devmapper
  • aufs
  • btrfs
  • zfs

這些驅動程式通常也被稱為圖形驅動程式(graph drivers),因為它們大多以圖形結構組織所處理的層。

在 Fedora 34 或更新版本上使用 Podman 時,容器的儲存組態檔案預設使用 overlay 驅動程式。

另一件需要注意的是,在撰寫本文時,overlay 檔案系統有兩個版本:版本 1 和版本 2。最初,Docker 容器引擎使用 overlay 檔案系統版本 1,但後來放棄了,轉而使用版本 2。這就是為什麼 Podman 和容器的儲存組態檔案通常使用 overlay 這個名稱,但實際上使用的是較新的版本 2。

OverlayFS:容器儲存的底層機制

在探討其他選項以及本章中的實際範例之前,讓我們先進一步瞭解其中一個 COW 檔案系統驅動程式的工作原理。

overlay 聯合檔案系統自 Linux 核心 3.18 版本以來就已存在。它通常預設啟用,並在啟動使用此檔案系統的掛載時動態啟用。

這種檔案系統背後的機制非常簡單但功能強大——它允許將一個目錄樹覆寫在另一個目錄樹上,僅儲存差異,但顯示最新更新的、合併後的目錄樹。

在容器的世界中,我們通常從一個唯讀檔案系統開始,新增一個或多個層,再次設為唯讀,直到一個正在執行的容器將這一堆積合併的層用作其根檔案系統。這時,最後一個讀寫層將被建立為其他層的覆寫層。

例項解析:Podman 下載容器映像檔的過程

讓玄貓來看看,當我們使用 Podman 下載一個全新的容器映像檔時,底層發生了什麼:

重要提示

如果您希望在測試機器上測試以下範例,請確保移除任何正在執行的容器和容器映像檔,以便輕鬆地將映像檔與 Podman 將為我們下載的層進行比對。

# podman pull quay.io/centos7/httpd-24-centos7:latest
Trying to pull quay.io/centos7/httpd-24-centos7:latest...
Getting image source signatures
Copying blob 5f2e13673ac2 done
Copying blob 8dd5a5013b51 done
Copying blob b2cc5146c9c7 done
Copying blob e17e89f32035 done
Copying blob 1b6c93aa6be5 done
Copying blob 6855d3fe68bc done
Copying blob f974a2323b6c done
Copying blob d620f14a5a76 done
Copying config 3b964f33a2 done
Writing manifest to image destination
Storing signatures
3b964f33a2bf66108d5333a541d376f63e0506aba8ddd4813f9d4e104271d9f0

從上面的命令輸出中,我們可以看到下載了多個層。這是因為我們下載的容器映像檔由多個層組成。

現在,我們可以開始檢查下載的層。首先,我們必須找到正確的目錄,我們可以在組態檔案中搜尋該目錄。或者,我們可以使用更簡單的技術。Podman 有一個專門用於顯示其執行組態和其他有用資訊的命令——podman info。讓玄貓來看看它是如何運作的:

# podman info | grep -A19 "store:"
store:
configFile: /etc/containers/storage.conf
containerStore:
number: 0
paused: 0
running: 0
stopped: 0
graphDriverName: overlay
graphOptions:
    overlay.mountopt: nodev,metacopy=on
graphRoot: /var/lib/containers/storage
graphStatus:
    Backing Filesystem: btrfs
    Native Overlay Diff: "false"
    Supports d_type: "true"
    Using metacopy: "true"
imageStore:
    number: 1
runRoot: /run/containers/storage
volumePath: /var/lib/containers/storage/volumes

為了減少 podman info 命令的輸出,我們使用了 grep 命令來僅比對包含容器儲存的目前組態的 store 部分。

正如我們所看到的,使用的驅動程式是 overlay,並且用於搜尋我們的層的根目錄被報告為 graphRoot 目錄:/var/lib/containers/storage;對於無根容器,等效路徑是 $HOME/.local/share/containers/storage。我們還有其他報告的路徑,但我們將在本文稍後討論這些路徑。關鍵字 graph 是一個術語,來源於我們之前介紹的驅動程式類別。

讓玄貓來看看這個目錄,看看實際內容是什麼:

# cd /var/lib/containers/storage
# ls
libpod  mounts  overlay  overlay-containers  overlay-images  overlay-layers  storage.lock  tmp  userns.lock

程式碼解密

  1. podman pull quay.io/centos7/httpd-24-centos7:latest: 這個指令使用 Podman 從 quay.io 容器映像檔倉函式庫下載 centos7/httpd-24-centos7 映像檔的最新版本。
  2. podman info | grep -A19 "store:": 這個指令使用 Podman 顯示系統資訊,然後使用 grep 過濾輸出,只顯示包含 “store:” 字串及其後 19 行的內容。這部分資訊包含了容器儲存的組態,例如使用的儲存驅動程式和根目錄。
    • podman info: 顯示 Podman 的系統資訊。
    • |: 管道符號,將 podman info 的輸出傳遞給 grep 命令。
    • grep -A19 "store:": 在輸入中搜尋包含 “store:” 的行,並顯示該行及其後 19 行。-A19 選項表示 “after” 19 行。
  3. cd /var/lib/containers/storage: 這個指令將目前工作目錄變更為 /var/lib/containers/storage。這是 Podman 預設儲存容器映像檔層的目錄。
  4. ls: 這個指令列出目前目錄中的所有檔案和目錄。在這個例子中,它顯示了 Podman 儲存層和其他相關檔案的目錄。

總而言之,這段程式碼示範瞭如何使用 Podman 下載容器映像檔,並檢查 Podman 的儲存組態,以瞭解映像檔層儲存在檔案系統上的哪個位置。