天天看點

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

作者 | Liu,Bo

來源|

阿裡巴巴雲原生公衆号

前言

常言道,startup 有 startup 的好,大廠有大廠的好,那麼大廠究竟好在哪呢?拿矽谷老牌大廠們 FLG 來說,如果要問最令人懷念的是什麼?Free food 和基礎設施(Infrastructure)一定是會上榜的,兩者均極大提升了廣大應用開發者的幸福指數。那麼能不能“讓天下沒有難做的應用”呢?請大家把目光投向正在興起的雲原生生态。

在雲原生生态中,容器服務包括了鏡像和容器引擎兩個部分。其中容器鏡像作為核心的雲原生應用制品,打包了完整的作業系統和應用運作環境,應用的疊代也因為使用了這種不可變架構而變得更簡單,更頻繁。

本文将圍繞着容器鏡像這一核心,分享它的相關知識和業界的思考與實踐。

容器鏡像的概念

1)容器鏡像

容器鏡像有一個官方的類比,"生活中常見的集裝箱",雖然擁有不同的規格,但箱子本身是不可變的(Immutable),隻是其中裝的内容不同。

對于鏡像來說,不變的部分包含了運作一個應用軟體(如 mysql)所需要的所有元素。開發者可以使用一些工具(如 Dockerfile)建構出自己的容器鏡像,簽名并上傳到網際網路上,然後需要運作這些軟體的人可以通過指定名稱(如 example.com/my-app)下載下傳、驗證和運作這些容器。

2)OCI 标準鏡像規範

在 OCI 标準鏡像規範出台之前,其實有兩套廣泛使用的鏡像規範,分别是 appc 和 docker v2.2,但“合久必分,分久必合”,有意思的是兩者的内容已經在各自的發展中逐漸同化了,是以 OCI 組織順水推舟地在 docker v2.2 的基礎上推出了 oci image format spec,規定了對于符合規範的鏡像,允許開發者隻要對容器打包和簽名一次,就可以在所有的容器引擎上運作該容器。

這份規範給出了 OCI image 的定義:

This specification defines an OCI Image, consisting of a manifest, 
an image index (optional), a set of filesystem layers, and a configuration.           

3)容器的工作流程

一個典型的容器工作流程是從由 developers 制作容器鏡像開始的(build),然後上傳到鏡像存儲中心(ship),最後部署在叢集中(run)。

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

容器鏡像技術發展中遇到的問題

不得不說,容器鏡像的設計是很出彩的,首先它蘊含了“完整的作業系統就是一個包”的優秀思想,帶着大家跳出了安裝包的思路,又提出了諸如 dockerfile 這樣的提升開發者體驗的 killer features,還能利用分層結構來節約時間空間。

不過,"金無足赤,人無完人",優秀的設計并不等于優秀的實踐,下面來聊一聊問題具體出在哪。

1. 容器鏡像使用者

1)問題一:啟動容器慢

容器啟動慢的情況普遍發生在當使用者啟動一個很大 size 的容器鏡像時,由于在容器準備階段需要三步(以 overlayfs 為例):

  • download 鏡像。
  • unpack 鏡像。
  • 使用 overlayfs 将容器可寫層和鏡像中的隻讀層聚合起來提供容器運作環境。

其中,download 鏡像時需要 download 整個鏡像,不能實作檔案資料按需加載。再加上 download 鏡像本身受限于網絡帶寬的影響,當容器鏡像 size 在到幾個 G 時,下載下傳時間會較長,破壞了容器原本優秀的使用者體驗。

2)問題二:較高的本地存儲成本

不同鏡像之間可以共享的最小機關是鏡像中的層,它的缺點之一是在 deduplication 上的效率是較低的,原因是:

  • 首先,層内部存在重複的資料。
  • 其次,層與層之間可能存在大量重複的資料,但即使有微小的差别,也會被作為不同的層。
  • 再次,根據 OCI image spec 對删除檔案和 hardlink 的設計,一個鏡像内部可能存在已經被上層删除的檔案仍然存在于下層中,并包含在鏡像中。

是以,當不同鏡像的容器被排程到同一台機器上運作時,鏡像本身在本地檔案系統中所占的存儲空間是一筆不可忽視的成本開銷。

2. 鏡像提供者側

這裡的提供者主要指容器服務的鏡像中心。

1)問題一:巨大的存儲浪費

  • 存在大量相似鏡像 造成這種情況有兩個原因:
    • 首先,上面提到的層的缺點,在容器鏡像中心會産生許多相似鏡像。
    • 其次,OCI image 使用了 tar+gzip 格式來表達鏡像中的層,而 tar 格式并不區分 tar archive entries ordering,這帶來一個問題,即如果使用者在不同機器上 build 去同一個鏡像,最終可能會因為使用了不同的檔案系統而得到不同的鏡像,然後使用者上傳之後,鏡像中心中會存在若幹不同鏡像的實質内容是完全相同的情況。
  • 鏡像去重效率低:雖然鏡像中心有垃圾回收來實作去重功能,但其仍然以層為機關,是以隻能在有完全相同 hash value 的層之間去重。

2)問題二:雲原生軟體供應鍊帶來的新需求

随着時間推移,和軟體供應鍊一起發展的還有對軟體供應鍊環節的多樣性攻擊手段。安全防護是軟體供應鍊中非常重要的組成,不光展現在對軟體本身的安全增強,也展現在對供應鍊本身的安全增強。而因為應用運作環境被前置到了容器鏡像中,是以對容器鏡像的安全,包括對鏡像的漏洞掃描和簽名成為了容器服務提供者的必要能力。

對容器鏡像的思考和讨論

1. 業界的嘗試

針對前面所述的問題,業界大小廠也是集思廣益,各顯神通,下面提幾個典型的項目:

1)CernVM-FS

使用了 fuse 按需從遠端加載需要的資料。

2)Slacker

通過設計一個鏡像的 benchmark 貢獻了幾個有意思的理論基礎:

  • 事實上,容器啟動時間很長。
  • 啟動時資料讀寫放大系數很大(啟動時中隻使用 6% 的資料)。
  • 分析了 57 個 docker image 的 layer 數量,發現一半以上的 image 的 layer 數量大于 9。

Slacker 最終使用了按需加載和減少鏡像層數将啟動速度提高了 5-20 倍。

3)SquashFs

Oracle 使用 Linux SquashFS 來替代 targz 存儲容器 image layer 的内容,去掉了 unpack tar 的環節。

2. OCI 社群中的讨論

自 2019 年開始,對于鏡像本身的吐槽慢慢多了起來,發酵了一年多,OCI 社群覺得時機成熟了,從 2020 年 6 月開始,花了一個多月時間密集讨論了目前 OCI 鏡像規範的缺陷,以及 OCIv2 鏡像格式(*)需要滿足哪些要求。

(*)OCIv2 在這裡隻是一個宣傳命名,實際上 OCIv2 是目前 OCI 鏡像規範的改進,而不會是一個全新的鏡像規範。

1)OCI 鏡像規範的缺陷

經過讨論得出目前的缺陷主要有兩點:

  • tar 格式标準
    • tar 格式并不區分 tar archive entries ordering,這帶來一個問題,即如果使用者在不同機器上去 build 同一個鏡像,最終可能會因為使用了不同的檔案系統而得到不同的鏡像,比如在檔案系統 A 上的 order 是 foo 在 bar 之前進入 tar,在檔案系統 B 上的 order 是 bar 在 foo 之前進入 tar,那麼這兩個鏡像是不同的。
    • 當 tar 被 gzip 壓縮過之後不支援 seek,導緻 run container 之前必須先下載下傳并解壓 targz 的 image layers,而不能實作檔案資料按需加載。
  • 以層為鏡像的基本機關
    • 内容備援:不同層之間相同資訊在傳輸和存儲時都是備援内容,在不讀取内容的時候無法判斷到這些備援的存在。
    • 無法并行:單一層是一個整體,對同一個層既無法并行傳輸,也不能并行提取。
    • 無法進行小塊資料的校驗,隻有完整的層下載下傳完成之後,才能對整個層的資料做完整性校驗。
    • 其他一些問題:比如,跨層資料删除難以完美處理。

2)下一代鏡像格式的要求

這次鏡像格式大讨論從一個郵件和一份共享文檔開始,并促成了多次線上的 OCI 社群讨論會議。最後的結論也很鼓舞人心,在這份共享文檔中可以找到對 OCIv2 鏡像格式需要滿足的要求的較長的描述。我們可以将這些要求分類為:

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

(*): 諸如 file timestamp 等隻在一個特定機器上有意義的 metadata 是沒有必要存在于鏡像中的。

可以看出,上面這些要求明确了容器鏡像的下一步重點在易用、效率、安全三個方面,達到在 "build - ship - run" 這三個階段協同優化的目的。

3. 阿裡雲在容器鏡像上的思考

阿裡雲一直積極地推動和發展雲原生生态,提供了基礎設施“阿裡雲容器鏡像服務(ACR)”作為使用者雲原生容器化的第一站,負責提供容器鏡像、Helm Chart 等 OCI Artifacts 管理和分發服務。同時我們也在結合容器業務現狀深化對容器鏡像格式的了解,不斷地總結什麼是滿足發展需求的容器鏡像格式,這裡可以概括為以下幾點,新的鏡像格式需要:

  • 滿足容器 "build once, run anywhere" 的理念。
  • 實作在鏡像中心和容器運作結點上存儲資源上的高效使用。
  • 在容器鏡像的全鍊路上(build, ship, run)比現有的 OCI 鏡像格式速度更快。
  • 能夠擴充在安全上的能力。
  • 最大程度相容已有基礎設施,普惠大多數使用者。

阿裡雲沙箱容器的鏡像加速

相比于社群的讨論重點放在了新的鏡像格式的設計上,阿裡雲更關心如何設計出一套優化全鍊路的鏡像方案,為客戶帶來能夠應用在生産中的價值。

在明确以上在技術發展過程中産生的需求之後,我們為

阿裡雲沙箱容器

設計了新的鏡像格式 Rafs,并為 CNCF 下的 Dragonfly 項目引入了容器鏡像服務,它能夠極大縮短鏡像下載下傳時間,并提供端到端的鏡像資料一緻性校驗,進而讓使用者能夠更安全快捷地管理容器應用。

1. Rafs: 鏡像格式

Rafs 把一個容器鏡像隻分成中繼資料和資料兩層。其中:

  • 中繼資料層:中繼資料層是一顆自校驗的哈希樹。每個檔案和目錄都是哈希樹中的一個附帶哈希值的節點。一個檔案節點的哈希值是由檔案的資料确定,一個目錄節點的哈希值則是由該目錄下所有檔案和目錄的哈希值确定。
  • 資料層:每個檔案的資料被按照固定大小切片并儲存到資料層中。資料切片可以在不同檔案以及不同鏡像中的不同檔案共享。
對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

2. Nydus: Dragonfly 的容器鏡像服務

除了使用上面的鏡像格式 Rafs,Nydus 還包含一個負責解析容器鏡像的 FUSE 使用者态檔案系統程序。

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

nydus 能夠解析 FUSE 或者

virtiofs

協定來支援傳統的

runC 容器

或者阿裡雲沙箱容器。容器倉庫、

OSS 對象存儲

、NAS、以及 Dragonfly 的超級節點和 peer 節點都可以作為 nydus 的鏡像資料源。同時,nydus 還可以配置一個本地緩存,進而避免每次啟動都從遠端資料源拉取資料。

基于這個設計架構,nydus 分别在 build, ship, run 和相容性方面提供下面這些優化:

對容器鏡像的思考和讨論前言容器鏡像技術發展中遇到的問題對容器鏡像的思考和讨論阿裡雲沙箱容器的鏡像加速總結

3. 為什麼選擇基于檔案的設計

在設計之初,Nydus 選擇了基于檔案的設計而不是基于塊的設計,為什麼這樣做呢?

主要的原因是,我們想在鏡像加速的基礎上做基于容器特點的附加能力,這一切都建立在能夠擷取到鏡像中的檔案中繼資料;而基于塊的設計隻使用 disk LBA,天然的無法擷取其上層(即檔案系統)中的資訊。

有了檔案中繼資料之後,我們輕松地實作了以下幾個增值功能:

  • 鏡像優化建議:在 build container 環節,提示使用者有哪些檔案是根本沒有通路過的,可以考慮借此來優化鏡像。
  • 預讀:在 run container 環節預加載,猜到使用者要讀檔案,那就預先在讀操作發生之前送過去,進而優化通路速度。
  • 安全審計:在 run container 環節,如果一個容器通路鏡像内容的模式和其他容器産生了明顯差異,那麼,這有可能是一個安全性風險。
  • 變更風險發現:在 run container 環節,如果一個鏡像更新之後,發現它通路内容的模式和之前發生了明顯差異,那麼,要麼是程式自己有意變了,要麼就可能是引入 bug 了,這時可以考慮提醒開發者這個變化。

總結

OCI image 分層鏡像機制雖然極大地友善了開發,但在大規模叢集運作時,也有頗多不足,對此,OCI 鏡像社群也在尋求着如何利用鏡像内容可感覺性,讓它更加快速、節省資源,也更加安全。阿裡雲在這個基礎上本着為客戶帶來價值的原則,提出了公有雲上對鏡像的穩定性、預讀等需求,并為阿裡雲沙箱容器研發出了相應的的鏡像加速方案,實作 "build-ship-run" 整個鏡像鍊路上的統一優化,讓使用者不光聽着熱鬧,也能用着開心,切實得到雲原生基礎設施發展的紅利。

點選參與“容器鏡像使用調查問卷”填寫

,将有 10 位随機獲贈阿裡雲容器鏡像服務(企業版)ACR EE 50 元優惠券哦~

繼續閱讀