下一代鏡像構(gòu)建工具 Buildkit 簡介

Buildkit 是 Docker 公司出品的一款更高效、docekrfile 無關、更契合[云原生應用]的新一代 Docker 構(gòu)建工具。
開源工具已經(jīng)不能滿足 DID 的需求
云原生的一個特點是一切基礎設施都是動態(tài)的,除了提供服務的基礎設施,CICD 的計算資源也趨向動態(tài)創(chuàng)建。很多企業(yè)已經(jīng)有了自己的 k8s 集群作為服務,自然而然開始思考如何把 CICD 搬到 k8s 中,各種 CI 工具的插件應運而生,而容器集群中的構(gòu)建成為了各種工具的焦點問題。
DID (Docker in docker 的演進)
最原始的 Docker in docker 是使用 privilege 將宿主機的一切權(quán)限共享給用于構(gòu)建的容器實例,這種方式容器可以獲得宿主機的最高權(quán)限,有很大風險,很快就被淘汰了。
目前比較普遍的做法,是把 Docker daemon 的 socket 掛在到用于構(gòu)建的容器中:
docker?run?-v?/var/run/docker.sock:/var/run/docker.sock?-it?docker
這種方式已經(jīng)經(jīng)歷了較長時間的驗證,可以滿足企業(yè)內(nèi)部使用的大部分場景:
遠程倉庫權(quán)限:對于 Docker credential 的隔離可以利用不同容器實例之間 Home directory 不同做到 緩存:同一臺宿主機上的緩存可以通過同一個 Docker daemon 共享 本地權(quán)限:由于不同容器實例掛在同一個宿主機的 Docker daemon 進程,所有實例里 docker 命令的權(quán)限也是共享的,也就是說不同容器實例可以查看甚至更新、刪除到同一個 Docker daemon 下別的容器實例構(gòu)建產(chǎn)生的鏡像。
本地權(quán)限的問題如果是在一個小企業(yè)內(nèi)部以共享賬號的方式或許還可以接受,稍微大一點的企業(yè)可以通過限制用戶輸入 Docker 命令,防止注入來規(guī)避權(quán)限盜用的風險。但目前看來這些方法都還是治標不治本,治本的方案要么是在 Docker daemon 建立一套權(quán)限機制,要么讓 Docker 里的構(gòu)建不依賴同一個 Docker daemon。
Build without docker daemon
社區(qū)中目前有三款工具可以支持無 docker daemon 化的構(gòu)建:kaniko,img 和 buildkit。
Kaniko 是由 Google 開發(fā)的在 k8s 上做 docker 構(gòu)建的命令行工具,使用非常簡潔,只需要 build 一個二進制工具即可,支持 dockerfile 構(gòu)建、push、credentail 文件讀取。 Buildkit 是 docker 公司開發(fā),目前由社區(qū)和 docker 公司合理維護的“含著金鑰匙出生”的新一代構(gòu)建工具,擁有良好的擴展性、極大地提高了構(gòu)建速度,以及更好的安全性,功能上配合 docker 使用還是沒問題的,獨立使用功能其實有殘缺,這個放到后面來講。 img 是社區(qū)貢獻者開發(fā),基于 buildkit 封裝的類 docker 化命令行工具,無需 daemon 進程,無需 privilege,可以獨立運行的二進制工具,非常小巧易用,而且有著和 buildkit 一樣的性能優(yōu)勢。
社區(qū)活躍度
kaniko > img > buildkit



可以看出三個工具中 kaniko 是 star 最多的項目, img 目前是缺少維護的狀態(tài),buildkit start 最少但是社區(qū)活躍度還比較高。
kaniko 踩坑
初步看來 kaniko 似乎是最佳選擇,大廠背書,相對活躍的社區(qū)和相對多的市場驗證。然而我們卻發(fā)現(xiàn)了當前版本(v0.9.0)的兩個不足:
Dockerfile 支持不全:由于實現(xiàn)方式和 docker 不同,kaniko 并不是完全兼容 dockerfile 的所有語法:例如多階段構(gòu)建中 FROM … AS xxx 的語法 xxx 首字母不能大寫;from 的鏡像系統(tǒng)文件無法在 build 的時候被覆蓋而是會報錯 緩存不能共享,kaniko 的緩存只能夠利用到基礎鏡像級別,即事先把鏡像放到緩存目錄下, kaniko 可以使用這個本地鏡像,而構(gòu)建過程中產(chǎn)生的鏡像 layers 則不能復用。docker 多階段構(gòu)建會有相當多的 dependency 中間產(chǎn)物,每次構(gòu)建都去下載這些依賴會極大地降低構(gòu)建速度從而帶來不好的體驗
基于以上兩點,kaniko 似乎仍是一個不夠成熟的工具,暫時不能投入生產(chǎn)。
img 踩坑
了解過 buildkit 的高性能之后,對 img 這樣集簡潔與性能于一身的工具可謂是滿懷期待,而事實卻不盡如人意,雖然 kaniko 遇到的 dockerfile img 都輕松支持了,但是在多階段鏡像構(gòu)建的時候似乎在并行構(gòu)建的處理上有些問題,對于復雜的多階段構(gòu)建會頻繁曝出 IO 異常,懷疑是缺少了 daemon 進程文件鎖的功能導致的,只好放棄。
Buildkit 介紹
最后來說說本文的主角:buildkit
Buildkit 是由 Docker 公司開發(fā)的下一代 docker build 工具,2018 年 7 月正式內(nèi)置于 Docker-ce 18.06.0 的 Docker daemon ,Mac 和 Linux 可以使用環(huán)境變量 DOCKER_BUILDKIT=1 開啟,同年 10 月發(fā)布社區(qū)版本。
相比于 Docker daemon build,buildkit:
更高效:支持并行的多階段構(gòu)建、更好的緩存管理; 更安全:支持 secret mount,無需 root priviliege; 更易于擴展:使用自定義中間語言 LLB,完全兼容 Dockerfile,也可支持第三方語言(目前僅有Buildpacks),后臺目前可支持 runC 和 containerd 兩種 worker。
目前社區(qū)除了 moby/docker-ce 外還在使用 buildkit 的項目有 genuinetools/img, openFaaS Cloud, containerbuilding/cbi。
與其他構(gòu)建工具對比

需要補充的一點是 buildkit 是對 Dockerfile 語法完全支持:

圖片來源:https://www.youtube.com/watch?v=kkpQ_UZn2uo
工作原理
buildkitd & buildctl
后臺啟動一個 buildkitd 守護進程,通過 http 通信的方式執(zhí)行構(gòu)建。
gRPC API: 使用 Google RPC 協(xié)議高效通信 Go client library:基于 Go 的客戶端方便調(diào)用 rootless execution:buildctl 不需要 root 權(quán)限就可以執(zhí)行 OpenTracing:支持鏡像 layer 的逐層溯源 multi-worker model:支持多種 worker(runC 和 containerd),可擴展
使用
安裝
官方鏡像:https://hub.docker.com/r/moby/buildkit
docker?run?--name?buildkit?-d?--privileged?-p?1234:1234?moby/buildkit?--addr?tcp://0.0.0.0:1234
export?BUILDKIT_HOST=tcp://0.0.0.0:1234
docker?cp?buildkit:/usr/bin/buildctl?/usr/local/bin/
buildctl?build?--help
Mac OS 在 https://github.com/moby/buildkit/releases 下載 buildctl
構(gòu)建
#?本地構(gòu)建
buildctl?--addr?tcp://localhost:1234?build?--frontend=dockerfile.v0?--local?context=.?--local?dockerfile=.
#?等同于?docker?build
buildctl?--addr?tcp://localhost:1234?build?--frontend=dockerfile.v0?--local?context=.?--local?dockerfile=.?--output?type=docker,name=myimage?|?docker?load
#?push
buildctl?build?--frontend?dockerfile.v0?--local?context=.?--local?dockerfile=.?--output?type=image,name=docker.io/username/image,push=true
權(quán)限
使用 docker credentials權(quán)限
可以使用環(huán)境變量 DOCKER_CONFIG 指定 credential 讀取路徑從而達到權(quán)限隔離(這方面缺少文檔,可以參考源碼):
https://github.com/moby/buildkit/blob/master/cmd/buildctl/build.go#L157
https://github.com/docker/cli/blob/master/cli/config/config.go#L127

緩存
buildkit 支持 layer 級別緩存,可指定緩存 export/import 路徑。
可以使用 registry 緩存:https://github.com/moby/buildkit#exportingimporting-build-cache-not-image-itself
不足
運行權(quán)限
Buildkitd 運行需要 privilege,這里有一個 issue 解釋說是因為 runC 讀寫宿主機文件系統(tǒng)需要 root 權(quán)限
穩(wěn)定性測試
跑了一個晚上的定時腳本,構(gòu)建的是同一個多階段鏡像,得到的結(jié)果不盡如人意:
速度不太穩(wěn)定,同一個鏡像在沒有網(wǎng)絡依賴的情況下構(gòu)建速度在 30s-10min 之間擺動

buildctl 和同一臺宿主機上的 buildkitd 通信不時會出現(xiàn)網(wǎng)絡問題,出現(xiàn)概率 10%

結(jié)論
Buildkit 似乎是一個很有前景的產(chǎn)品,只是目前還沒有達到生產(chǎn)環(huán)境需要的水平。
我比較看好它的設計,比如內(nèi)置文件數(shù)據(jù)庫,中心化調(diào)度思維,前后端可擴展,權(quán)限擴展單元,這些都是云原生時代需要的,只是產(chǎn)品的打磨還需要加以時日,以及市場的礪煉。
原文鏈接:https://www.duyidong.com/2019/05/19/build-image-in-container-via-buildkit/
CKA 認證培訓(降價啦)
?點擊屏末?|?閱讀原文?|?即刻學習
