Nydus 加速映象一致性校驗增強

SOFAStack發表於2023-01-31

導言:

GitLink 程式設計夏令營是在 CCF 中國計算機學會指導下,由 CCF 開源發展委員會(CCF ODC)舉辦的面向全國高校學生的暑期程式設計活動。
這是去年(2022)的夏令營活動中,王瑞同學參加 Nydus 開源專案的總結,主要介紹了為 Nydus 支援映象與檔案系統一致性校驗所做的相關工作。

Nydus 簡介

Nydus 是 CNCF 孵化專案 Dragonfly 的子專案,它提供了容器映象,程式碼包,資料分析按需載入的能力,無需等待整個資料下載完成便可開始服務。

Nydus 在生產環境已經支撐了每日百萬級別的加速映象容器建立,在啟動效能,映象空間最佳化,網路頻寬效率,端到端資料一致性等方面相比 OCIv1 格式有著巨大優勢,並可擴充套件至例如 NPM 包懶載入等資料分發場景。

目前 Nydus 由螞蟻集團,阿里雲,位元組跳動聯合開發,Containerd,Podman 社群接受了 Nydus 執行時作為其社群子專案,也是 KataContainers 以及 Linux v5.19 核心態原生支援的映象加速方案。

Nydus 架構及原理

OCI 容器映象是當前容器映象的實現標準。它採用了分層的設計,每個映象可包含多個映象層。新層包含的是在舊層的基礎上,新增加或者修改的檔案或者被刪除的檔案。這種設計方式比較簡單,不過也有著一定的缺陷。如需要映象層全部堆疊後才能看到整個檔案系統的檢視,但不是所有資料都會被讀取;同時可能已經刪除或者被修改舊層中的檔案,但是仍需要完整地下載和解壓舊層;檔案後設資料修改導致整個映象層被重新儲存等。 Nydus 相容目前的 OCI 生態,旨在透過細粒度的資料分割、去重和按需載入機制加速容器 的啟動和分發,同時降低資源的消耗。

Nydus 的整體架構如下圖所示。它可以透過 FUSE 給 runc 容器提供執行時的按需載入能力,也可以透過 virtiofs 承載 FUSE 協議,給 Kata Containers 等基於 VM 的容器執行時提供按需載入的能力。它可以從容器 Registry,OSS,NAS,Dragonfly supernode 等多個映象源拉取映象,同時內部會有本地的快取加速容器的建立。

img

img

在使用者空間檔案系統,Nydus 採用了資料和後設資料分離的設計思想,後設資料的修改不會導致整個映象層的更新。原先的映象層只儲存檔案的資料部分,同時資料被分塊儲存。拉取映象是不需要拉取整層,只需要拉取所需檔案對應的資料塊即可。這也使得層與層之間,映象與映象之間共享資料塊更加容易。上圖展示了 Nydus 資料和後設資料的儲存格式。其中後設資料以 merkle tree 的形式儲存在 bootstrap 中,包含了容器啟動所需要的資訊。資料以 1MB 分塊儲存,不同映象可以共享同一資料塊。

Nydus 映象校驗意義及流程

Nydus 映象在構建完成後,由於網路、磁碟等故障或者映象被惡意修改,無法保證容器啟動前映象是合法的,所以需要對映象的格式進行校驗。當前的校驗使用 nydusify 工具。主要分為三個部分:

  1. 對 Nydus 映象的 bootstrap 進行校驗,會透過 BootstrapRule 呼叫 nydus-image 二進位制檔案。nydus-image 首先檢查 bootstrap 的 SuperBlock 格式是否正確,然後會從根結點開始按照檔案系統層級結構檢查檔案或者目錄的 inode 是否合法或被修改。
  2. 對映象的 manifest 進行校驗,會透過 ManifestRule 檢驗 Nydus 的 manifest 是否合法,ImageConfig 是否與原始 OCI 映象一致等。
  3. 對映象進行檔案系統校驗,會透過 FilesystemRule 分別掛載原始 OCI 映象和 Nydus 映象,然後進行校驗。對於原始映象,會使用 docker pull 拉取映象,然後指定 lowerdir 和 upperdir,透過 OverlayFS 掛載 Rootfs;對於 Nydus 映象,會使用 Nydusd 掛載。掛載完成後,會分別遍歷兩個目錄,比較後設資料和資料是否一致。

目前 Nydus 的校驗方式仍有一定的限制,如後設資料檢查不完全,需要 docker 拉取映象等。該專案旨在增強 nydusify 和 nydus-image 的校驗功能,使校驗更加易用和全面。

檔案系統校驗方案

該專案當前分為以下三部分:

  1. 當前 nydusify check 在應用 FilesystemRule 進行校驗時,對於檔案後設資料只檢查檔案路徑、大小、模式和許可權位以及 xattrs 是否和原始映象一致,同時對檔案資料用 blake3 計算得到雜湊值並進行比較。但是由於校驗內容不完整,可能會出現後設資料不一致校驗透過的情況。故對該結構體新增 dev、rdev、symlink、project id、uid、gid、nlink、ctime 等欄位,實現對檔案後設資料更全面的檢查。

img

  1. 當前 nydusify check 在應用 FilesystemRule 進行校驗時,需要手動指定 source 和 Backend Type, Backend Config 才能成功應用 Nydusd 掛載並進行檔案系統校驗,在校驗資料時,也會再次檢查 Backend Type 是否指定。在大多數情況下,Backend Type 為 Registry,Backend Config 可以透過檢視 Registry 的 config 檔案獲取相關資訊,如 http.addr 欄位獲取地址,auth 欄位獲取認證資訊等獲取。因而使用者在很多情況下並不需要手動輸入上述引數。該任務旨在簡化該命令,實現 Backend Type,Backend Config 的自動推斷,使得使用者更方便地進行校驗。

img

(3) 當前 nydusify check 在應用 FilesystemRule 進行校驗時,需要使用者安裝 docker,因為要使用 docker pull 命令拉取映象。在沒有 docker 的環境下,無法完成校驗。可以修改該部分程式碼,手動下載、解壓映象,並使用 OverlayFS 掛載,從而去除對 docker 的依賴。

img

檔案系統校驗實現細節

增加校驗欄位

該部分的實現較為簡單。首先在原 Node 結構體增加 rdev, symlink, uid, gid, mtime 等欄位。

img

然後在遍歷檔案系統時,使用 Readlink 獲取檔案的軟連結,透過 Lstat 系統呼叫獲取 檔案更詳細的後設資料資訊(rdev, uid, gid, mtime 等),從而在進行比較時增加對上述欄位的校驗。值得注意的是 dev 不同是正常的,nlink 由於 OverlayFS 的問題無法進行校驗。此外,還需要修改異常錯誤資訊,從而遇到不一致時能夠列印完整的檔案後設資料資訊。

img

簡化校驗引數

該部分需要實現 Backend Type 和 Backend Config 的自動推斷,即如果映象儲存在 registry 中,使用者無需指定上述兩個引數即可完成校驗。

img

首先,我們需要新增上述結構體,即映象源為 Registry 時的 Backend Config。對於 FilesystemRule 結構體,還需新增 Target 和 TargetInsecure 欄位,用於填充 Backend Config。

img

在掛載 Nydus 映象時,我們需要正確填充 Nydusd 的 config,其中便包含 Backend Config 和 Backend Type。因此我們對使用者傳入的引數進行判斷,如果使用者沒有傳入 Backend Type,那麼我們預設映象源為 registry,如果沒有傳入 Backend Config,那麼我們透過 target 提取 host 和 repo,然後讀取 docker 的 config 獲取 auth 相關的資訊,最後生成 Backend Config。

除此之外,由於我們目前的測試程式碼中不涉及使用者鑑權,所以額外新增了 testBasicAuth 測試樣例,用於檢驗在使用者不指定 Backend Config 時,我們是否能夠正確提供 鑑權資訊。在測試樣例中,我們模擬生成了使用者名稱、密碼和 docker config,並正確設定了環境變數 。 啟動 docker 時 ,額外指定REGISTRY_AUTH_HTPASSWD_PATH , REGISTRY_AUTH 等用於鑑權。

實現無需 docker 拉取映象

當前拉取原始映象時,我們需要事先安裝 docker,然後透過 docker pull 指令拉取。我們可以手動的拉取每個映象層,然後解壓、掛載,從而去除對 docker 的依賴。

首先我們需要在 FilesystemRule 結構體中新增 SourceParsed, SourcePath, SourceRemote 等欄位,指定原始映象的相關資訊和儲存路徑。在拉取原始映象時,我們透過 SourceParsed 獲取到映象層的資訊,然後多執行緒下載每個映象層並解壓。

img

因為映象的儲存路徑是事先確定的,同時我們也可以獲取到每個映象層的資訊,所以在掛載映象時,我們不需要執行 docker inspect 命令獲取映象的分層資訊,可以直接拼接每一層的路徑,使用 OverlayFS 進行掛載。

img

後續發現 OverlayFS 掛載單層映象時存在一定的問題,因而上述程式碼進行了一定程度 的修改和重構。

收穫與展望

這個專案的程式碼量不是很大,但是我從中學習到了很多。首先透過閱讀程式碼和跟蹤除錯,我瞭解了 Nydus 的設計思想和映象的生成及校驗的流程。在完成專案的過程中,我對 go 語言的使用更加熟練,對於容器映象的分層儲存格式及拉取、掛載的流程有了更加 細化的認識。透過解決測試過程中遇到的各種問題,我發現問題、定位問題、解決問題的能力也有了一定的提升。希望之後有機會可以繼續參與到 Nydus 專案之中,為開源貢獻力量。

作者有話說

哈嘍大家好,我是王瑞,本科畢業於北京郵電大學電腦科學與技術專業,現就讀於多倫多大學,從事日誌壓縮相關研究。本科時曾在位元組跳動公司實習,參與過自動化運維平臺、儲存系統記憶體管理相關的開發工作。也曾在 VMware 公司實習,為開源資料庫 GreenPlum 貢獻過程式碼。因為對雲原生比較感興趣,所以非常高興可以參與到 Nydus 這個專案。感謝嚴松老師在過程中提供的指導和幫助。

Nydus Star 一下✨:

github.com/dragonflyos…

本週推薦閱讀

Nydus 映象掃描加速

Nydus 映象加速外掛遷入 Containerd 旗下

Nydus | 容器映象基礎

Dragonfly 和 Nydus Mirror 模式整合實踐

相關文章