近期 Zeabur 因受到 zbpack v1 既有基礎設施淘汰的影響,正在向所有使用者推送新一代建構系統(zbpack v2)的更新。升級過程中已知造成了一些相容性的問題,而這裡會說明問題的緣由、處理方式,以及如果你遇到這個問題時,可以怎麼緩解這個問題。
Zeabur 背後的編譯基礎設施是這樣運作的:
「registry v1」是使用 distribution/distribution 的 registry 架設的,由於其造成的種種問題,促使我們遷移到自行設計的 registry v2 方案:
blob unknown
的錯誤並拒絕上傳 manifest,導致啟動時無法拉取映像distribution/distribution
傾向做全域 blob 去重,導致我們這裡無法在不讀取所有 manifest 的情況下,了解哪些 blobs 是用不到的。官方提供的垃圾清理 (garbage collection) 工具是要求停機執行 (stop-the-world) 的,在 Zeabur 如此大的 registry 規模下無法運作,導致 R2 累積了非常大量的 blobs,並因此造成相當嚴重的效能問題我們將 registry v2 設計成「建構 OCI image」後「直接推上 R2 bucket」,接著再使用 Cloudflare Workers,撰寫一個可以將 bucket 中 OCI image 結構轉換成符合 OCI Distribution Specification 裡面 Pull API 的 read-only API。這樣一來,除了效能可以獲得極大提升、可以最大化 multipart 上傳的效率,也可以避免因 registry 造成的種種問題。與此同時,我們將 blob 的去重限定在 repo 內部,因此可以做到「刪掉一個 repo 就能 gc 掉其對應的 blobs」,極大簡化內部維護且無需 stop-the-world。
不過從上面的描述中,也能看到 registry v2 的 push 流程有著相當大的變化。這部分已經在 zbpack v2 中得到實作,但 zbpack v1 由於其複雜的推送流程,以及很大依賴 buildkit CLI 進行 image 的建構,導致實作這部分較為困難,因此近一個月,我們讓屬於 zbpack v1 的專案繼續使用 zbpack v1(registry v1)編譯,惟當使用者回報 zbpack v1 無法啟動時,才手動切換到 zbpack v2 上。
但當 registry v1 愈來愈不堪重負,出錯頻率節節攀升,導致類似工單愈來愈多時,我們不得不考慮將 zbpack v1 負責 image 的部分,轉換到 zbpack v2 上。
眼尖的開發者,應該有注意到 zbpack (v1) 的 GitHub Repo 從 Archived 轉回維護狀態,並且提交了很多和 Dockerfile 相關的更新。實際上,這部分就是在為 zbpack v1 轉接到 zbpack v2 的相容層做準備。
我們希望維持 zbpack v1 既有的 Dockerfile 產生功能,但在產完 Dockerfile 後不使用 zbpack v1 內建的建構邏輯,而是切換到 zbpack v2 上。因此,我們將 v1 現有的 Dockerfile 產生功能改為公開函式,並讓建構服務使用這個函式產出 Dockerfile,再傳遞到執行 zbpack v2 的編譯機器上。
不過 zbpack v1 畢竟最初是設計在編譯機器上運作的,有諸多部分是需要進行實作或轉接的:
因此,我們實作了 zbpack v1 相容層,移植 zbpack v1 編譯機器對於 zbpack v1 呼叫的處理。絕大部分明顯的問題(如程式碼讀取),我們在全域推送前都已經解決了,且在測試機器上進行內部測試時,沒有遇到判斷失誤的狀況,同時也有派駐 on-call 工程師持續關注推送帶來的影響。然而在實際推送到所有機器上時,卻發現了諸多新相容層沒有考慮到的問題。舉例來說:
ZBPACK_
開頭的變數失效ZBPACK_DOCKERFILE_NAME
行為與先前不一致考慮到部分情境沒有其對應的測試環境,以及評估回退版本造成的影響可能更大,我們在 on call 時遇到這些問題時,決定將錯就錯,快速地執行「修正」、「測試」、「推送」的流程,同時也向客戶提供 workaround 緩解問題。我們在 8/26 - 8/27 這段期間很快地實作完整 zbpack 的相容層、實作了 plan type 和 plan meta 的展示,並給 registry v2 設計了大陸 CDN 來加速下載。
非常感謝所有回報這些問題的客戶,讓我們發現相容層沒有涵蓋到的 edge cases 並促使我們研究並修正。
上面提出的問題,相容層均已實作或修正。如果有其他不完整的部分,也請開單讓我們的工程師處理。
目前已知的問題如下:
PORT=對外連線埠
(如 PORT=8080
)緩解這個問題概觀本次事故,核心原因有幾個:
如果您是這次受到影響的客戶,我們可以提供影響時間折算的 credit 進行補償。未來我們在推送這部分功能時會更加謹慎,也非常感謝所有發現相容層問題的客戶。