Skip to content

淺談 Moby’s BuildKit

  • Dev, Ops

前陣子因為工作需要,研究了一下所謂 Docker build 的 3.0 版本 —— docker buildx build,希望能找出其與 docker build 背後的差異

docker buildx 指令是使用 Moby’s BuildKit 這套工具來代理 building,所以以下會用 BuildKit 來指稱新的建構模式

直接下結論

  • BuildKit 須要透過一個前端服務去轉換 Dockerfile (或其他語言定義的建構流程),再交給 LLB 處理
  • 即使是同一個 Dockerfile,docker build/buildx 兩者建構出的 layer 完全不同,無法共享
  • 如果你建構很複雜,已經有在使用 multi-stage build(例如須要先編譯成二進制檔案),那會比較有幫助,如果是要 build 類似 python 這種直譯式的應用程式,因為流程較為單純所以幫助不大

原理

要了解背後實作的差異,會需要知道幾個背景知識:

  1. Docker、BuildKit 跟 containerd 的關係
  2. Overlay Filesystem
  3. containerd 的 snapshotter

Docker、BuildKit 跟 containerd 的關係

containerd 原本是 Docker 的底層服務,用來:

  • 管理容器的 content (包含 filesystem、config、metadata、image)
  • 負責 container 的啟動、刪除(透過 runc 調用 kernel)

containerd 後來從 Docker 抽離出來,變成專門管理容器的服務,且支援公開協議 Container Runtime Interface(CRI),其他上層的實現可以直接拿來用,例如 Kubernetes 就是使用者之一

img

BuildKit 就作用於 Docker 與 containerd 之間,為了取代 docker build 而生

Overlay Filesystem

overlay 是 containerd 預設的 storage driver,背後透過 union mount,讓 container 可以共享 filesystem,以節省空間並加快容器的啟動速度

若在 upper layer 更動了 lower layer 的檔案,會先做 copy-on-write,將變動的檔案先複製一份到 upper layer,並確保 lower layer 的檔案都是唯讀的

containerd 的 snapshotter

snapshot 跟 layer 一樣,都是屬於 containerd 的 content,要理解 snapshot 要先知道 layer 怎麼被儲存的

先來看一下映像檔(.json)所描述的 layers:

每一層 layer 的 hash 如 24302eb7d9085da80f016e7e4ae55417e412fb7e0a8021e95e3b60c67cde557d 都是指向一個「未壓縮的 tar」,可以把他看作一個檔案系統的目錄,存放在 /var/lib/containerd/io.containerd.content.v1.content/blobs/sha256 ,而這些目錄全都是唯讀的

如果都是唯讀,那為什麼在容器中可以做檔案寫入?

這邊就會需要 snapshot 了,snapshot 把實體的 layer 抽象出來,提供一個可讀寫檔案的介面

首先 containerd 會幫每個 layer 做一份快照,每個快照都會指向另一個 parent 快照,是一個 parent-pointer-tree 的資料結構

做快照的方式(很像 git 的快照,可以一起理解):

當要啟動一個容器時,containerd 就會根據 image json 定義的 layers,準備好這一連串的 snapshots,然後在最上層疊加一個「active 的快照」,專門給這個容器用,讓容器的檔案系統變成是可寫的,不再是 immutable

img

想像一下你可以對一個 active 的快照做各種掛載,且一樣具備 copy-on-write 的機制,還能隨意操作不用擔心會影響到原始檔案,雖然我不是 snapshot 專家,但這聽起來很不錯對吧?

總結

snapshot 是 layer 的抽象界面,其背後真實的檔案系統可以是 overlayvfsbtrfs

利用 snapshot 的樹狀結構,BuildKit 可以更有彈性地去建構 content 的依賴關係,而不用受限於傳統 docker build 只有一維陣列的依賴關係

References

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。