再見 Dockerfile,擁抱新型鏡像構(gòu)建技術(shù) Buildpacks

云原生正在吞并軟件世界,容器改變了傳統(tǒng)的應(yīng)用開發(fā)模式,如今研發(fā)人員不僅要構(gòu)建應(yīng)用,還要使用 Dockerfile 來完成應(yīng)用的容器化,將應(yīng)用及其依賴關(guān)系打包,從而獲得更可靠的產(chǎn)品,提高研發(fā)效率。
隨著項(xiàng)目的迭代,達(dá)到一定的規(guī)模后,就需要運(yùn)維團(tuán)隊(duì)和研發(fā)團(tuán)隊(duì)之間相互協(xié)作。運(yùn)維團(tuán)隊(duì)的視角與研發(fā)團(tuán)隊(duì)不同,他們對(duì)鏡像的需求是安全和標(biāo)準(zhǔn)化。比如:
不同的應(yīng)用應(yīng)該選擇哪種基礎(chǔ)鏡像? 應(yīng)用的依賴有哪些版本? 應(yīng)用需要暴露的端口有哪些?
為了優(yōu)化運(yùn)維效率,提高應(yīng)用安全性,研發(fā)人員需要不斷更新 Dockerfile 來實(shí)現(xiàn)上述目標(biāo)。同時(shí)運(yùn)維團(tuán)隊(duì)也會(huì)干預(yù)鏡像的構(gòu)建,如果基礎(chǔ)鏡像中有 CVE 被修復(fù)了,運(yùn)維團(tuán)隊(duì)就需要更新 Dockerfile,使用較新版本的基礎(chǔ)鏡像??傊?,運(yùn)維與研發(fā)都需要干預(yù) Dockerfile,無法實(shí)現(xiàn)解耦。
為了解決這一系列的問題,涌現(xiàn)出了更加優(yōu)秀的產(chǎn)品來構(gòu)建鏡像,其中就包括 Cloud Native Buildpacks[1] (СNB)。CNB 基于模塊化提供了一種更加快速、安全、可靠的方式來構(gòu)建符合 OCI 規(guī)范的鏡像,實(shí)現(xiàn)了研發(fā)與運(yùn)維團(tuán)隊(duì)之間的解耦。
在介紹 CNB 之前,我們先來闡述幾個(gè)基本概念。
符合 OCI 規(guī)范的鏡像
如今,容器運(yùn)行時(shí)早就不是 Docker 一家獨(dú)大了。為了確保所有的容器運(yùn)行時(shí)都能運(yùn)行任何構(gòu)建工具生成的鏡像,Linux 基金會(huì)與 Google,華為,惠普,IBM,Docker,Red Hat,VMware 等公司共同宣布成立開放容器項(xiàng)目(OCP),后更名為開放容器倡議(OCI)[2]。OCI 定義了圍繞容器鏡像格式和運(yùn)行時(shí)的行業(yè)標(biāo)準(zhǔn),給定一個(gè) OCI 鏡像,任何實(shí)現(xiàn) OCI 運(yùn)行時(shí)標(biāo)準(zhǔn)[3]的容器運(yùn)行時(shí)都可以使用該鏡像運(yùn)行容器。
如果你要問 Docker 鏡像與 OCI 鏡像之間有什么區(qū)別,如今的答案是:幾乎沒有區(qū)別。有一部分舊的 Docker 鏡像在 OCI 規(guī)范之前就已經(jīng)存在了,它們被稱為 Docker v1 規(guī)范,與 Docker v2 規(guī)范是不兼容的。而 Docker v2 規(guī)范捐給了 OCI,構(gòu)成了 OCI 規(guī)范的基礎(chǔ)。如今所有的容器鏡像倉(cāng)庫(kù)、Kubernetes 平臺(tái)和容器運(yùn)行時(shí)都是圍繞 OCI 規(guī)范建立的。
什么是 Buildpacks
Buildpacks 項(xiàng)目最早由 Heroku 在 2011 年發(fā)起, 被以 Cloud Foundry 為代表的 PaaS 平臺(tái)廣泛采用。
一個(gè) buildpack 指的就是一個(gè)將源代碼變成 PaaS 平臺(tái)可運(yùn)行的壓縮包的程序,通常情況下,每個(gè) buildpack 封裝了單一的語(yǔ)言生態(tài)系統(tǒng)的工具鏈,例如 Ruby、Go、NodeJs、Java、Python 等都有專門的 buildpack。
你可以將 buildpack 理解成一坨腳本,這坨腳本的作用是將應(yīng)用的可執(zhí)行文件及其依賴的環(huán)境、配置、啟動(dòng)腳本等打包,然后上傳到 Git 等倉(cāng)庫(kù)中,打好的壓縮包被稱為 droplet。
然后 Cloud Foundry 會(huì)通過調(diào)度器選擇一個(gè)可以運(yùn)行這個(gè)應(yīng)用的虛擬機(jī),然后通知這個(gè)機(jī)器上的 Agent 下載應(yīng)用壓縮包,按照 buildpack 指定的啟動(dòng)命令,啟動(dòng)應(yīng)用。
到了 2018 年 1 月,Pivotal 和 Heroku 聯(lián)合發(fā)起了 Cloud Native Buildpacks(CNB)[4] 項(xiàng)目,并在同年 10 月讓這個(gè)項(xiàng)目進(jìn)入了 CNCF。

2020 年 11 月,CNCF 技術(shù)監(jiān)督委員會(huì)(TOC)投票決定將 CNB 從沙箱項(xiàng)目晉升為孵化項(xiàng)目[5]。是時(shí)候好好研究一下 CNB 了。
為什么需要 Cloud Native Buildpacks
Cloud Native Buildpacks(CNB) 可以看成是基于云原生的 Buildpacks 技術(shù),它支持現(xiàn)代語(yǔ)言生態(tài)系統(tǒng),對(duì)開發(fā)者屏蔽了應(yīng)用構(gòu)建、部署的細(xì)節(jié),如選用哪種操作系統(tǒng)、編寫適應(yīng)鏡像操作系統(tǒng)的處理腳本、優(yōu)化鏡像大小等等,并且會(huì)產(chǎn)出 OCI 容器鏡像,可以運(yùn)行在任何兼容 OCI 鏡像標(biāo)準(zhǔn)的集群中。CNB 還擁抱了很多更加云原生的特性,例如跨鏡像倉(cāng)庫(kù)的 blob 掛載和鏡像層級(jí) rebasing[6]。
由此可見 CNB 的鏡像構(gòu)建方式更加標(biāo)準(zhǔn)化、自動(dòng)化,與 Dockerfile 相比,Buildpacks 為構(gòu)建應(yīng)用提供了更高層次的抽象,Buildpacks 對(duì) OCI 鏡像構(gòu)建的抽象,就類似于 Helm 對(duì) Deployment 編排的抽象。
2020 年 10 月,Google Cloud 開始宣布全面支持 Buildpacks,包含 Cloud Run、Anthos 和 Google Kubernetes Engine (GKE)。目前 IBM Cloud、Heroku 和 Pivital 等公司皆已采用 Buildpacks,如果不出意外,其他云供應(yīng)商很快就會(huì)效仿。
Buildpacks 的優(yōu)點(diǎn):
針對(duì)同一構(gòu)建目的的應(yīng)用,不用重復(fù)編寫構(gòu)建文件(只需要使用一個(gè) Builder)。 不依賴 Dockerfile。 可以根據(jù)豐富的元數(shù)據(jù)信息(buildpack.toml)輕松地檢查到每一層(buildpacks)的工作內(nèi)容。 在更換了底層操作系統(tǒng)之后,不需要重新改寫鏡像構(gòu)建過程。 保證應(yīng)用構(gòu)建的安全性和合規(guī)性,而無需開發(fā)者干預(yù)。

Buildpacks 社區(qū)還給出了一個(gè)表格來對(duì)比同類應(yīng)用打包工具:

可以看到 Buildpacks 與其他打包工具相比,支持的功能更多,包括:緩存、源代碼檢測(cè)、插件化、支持 rebase、重用、CI/CD 多種生態(tài)。
Cloud Native Buildpacks 工作原理
Cloud Native Buildpacks 主要由 3 個(gè)組件組成:Builder、Buildpack 和 Stack。
Buildpack
Buildpack 本質(zhì)是一個(gè)可執(zhí)行單元的集合,一般包括檢查程序源代碼、構(gòu)建代碼、生成鏡像等。一個(gè)典型的 Buildpack 需要包含以下三個(gè)文件:
buildpack.toml – 提供 buildpack 的元數(shù)據(jù)信息。 bin/detect – 檢測(cè)是否應(yīng)該執(zhí)行這個(gè) buildpack。 bin/build – 執(zhí)行 buildpack 的構(gòu)建邏輯,最終生成鏡像。
Builder
Buildpacks 會(huì)通過“檢測(cè)”、“構(gòu)建”、“輸出”三個(gè)動(dòng)作完成一個(gè)構(gòu)建邏輯。通常為了完成一個(gè)應(yīng)用的構(gòu)建,我們會(huì)使用到多個(gè) Buildpacks,那么 Builder 就是一個(gè)構(gòu)建邏輯的集合,包含了構(gòu)建所需要的所有組件和運(yùn)行環(huán)境的鏡像。
我們通過一個(gè)假設(shè)的流水線來嘗試?yán)斫?Builder 的工作原理:

最初,我們作為應(yīng)用的開發(fā)者,準(zhǔn)備了一份應(yīng)用源代碼,這里我們將其標(biāo)識(shí)為 “0”。 然后應(yīng)用 “0” 來到了第一道工序,我們使用 Buildpacks1 對(duì)其進(jìn)行加工。在這個(gè)工序中,Buildpacks1 會(huì)檢查應(yīng)用是否具有 “0” 標(biāo)識(shí),如果有,則進(jìn)入構(gòu)建過程,即為應(yīng)用標(biāo)識(shí)添加 “1”,使應(yīng)用標(biāo)識(shí)變更為 “01”。 同理,第二道、第三道工序也會(huì)根據(jù)自身的準(zhǔn)入條件判斷是否需要執(zhí)行各自的構(gòu)建邏輯。
在這個(gè)例子中,應(yīng)用滿足了三道工序的準(zhǔn)入條件,所以最終輸出的 OCI 鏡像的內(nèi)容為 “01234” 的標(biāo)識(shí)。
對(duì)應(yīng)到 Buildpacks 的概念中,Builders 就是 Buildpacks 的有序組合,包含一個(gè)基礎(chǔ)鏡像叫 build image、一個(gè) lifecycle 和對(duì)另一個(gè)基礎(chǔ)鏡像 run image 的應(yīng)用。Builders 負(fù)責(zé)將應(yīng)用源代碼構(gòu)建成應(yīng)用鏡像(app image)。

build image 為 Builders 提供基礎(chǔ)環(huán)境(例如 帶有構(gòu)建工具的 Ubuntu Bionic OS 鏡像),而 run image 在運(yùn)行時(shí)為應(yīng)用鏡像(app image)提供基礎(chǔ)環(huán)境。build image 和 run image 的組合被稱為 Stack[7]。
Stack
上面提到,build image 和 run image 的組合被稱為 Stack,也就是說,它定義了 Buildpacks 的執(zhí)行環(huán)境和最終應(yīng)用的基礎(chǔ)鏡像。
你可以將 build image 理解為 Dockerfile 多階段構(gòu)建中第一階段的 base 鏡像,將 run image 理解為第二階段的 base 鏡像。
上述 3 個(gè)組件都是以 Docker 鏡像的形式存在,并且提供了非常靈活的配置選項(xiàng),還擁有控制所生成鏡像的每一個(gè) layer 的能力。結(jié)合其強(qiáng)大的 caching[8] 和 rebasing[9] 能力,定制的組件鏡像可以被多個(gè)應(yīng)用重復(fù)利用,并且每一個(gè) layer 都可以根據(jù)需要單獨(dú)更新。
Lifecycle 是 Builder 中最重要的概念,它將由應(yīng)用源代碼到鏡像的構(gòu)建步驟抽象出來,完成了對(duì)整個(gè)過程的編排,并最終產(chǎn)出應(yīng)用鏡像。下面我們單獨(dú)用一個(gè)章節(jié)來介紹 Lifecycle。
構(gòu)建生命周期(Lifecyle)
Lifecycle 將所有 Buildpacks 的探測(cè)、構(gòu)建過程抽離出來,分成兩個(gè)大的步驟聚合執(zhí)行:Detect 和 Build。這樣一來就降低了 Lifecycle 的架構(gòu)復(fù)雜度,便于實(shí)現(xiàn)自定義的 Builder。
除了 Detect 和 Build 這兩個(gè)主要步驟,Lifecycle 還包含了一些額外的步驟,我們一起來解讀。
Detect
我們之前提到,在 Buildpack 中包含了一個(gè)用于探測(cè)的 /bin/detect 文件,那么在 Detect 過程中,Lifecycle 會(huì)指導(dǎo)所有 Buildpacks 中的 /bin/detect 按順序執(zhí)行,并從中獲取執(zhí)行結(jié)果。
那么 Lifecycle 把 Detect 和 Build 分開后,又是怎么維系這兩個(gè)過程中的關(guān)聯(lián)關(guān)系呢?
Buildpacks 在 Detect 和 Build 階段,通常都會(huì)告知在自己這個(gè)過程中會(huì)需要哪些前提,以及自己會(huì)提供哪些結(jié)果。

在 Lifecycle 中,提供了一個(gè)叫做 Build Plan 的結(jié)構(gòu)體用于存放每個(gè) Buildpack 的所需物和產(chǎn)出物。
type?BuildPlanEntry?struct?{
????Providers?`toml:“providers”`
????Requires??`toml:"requires"`
同時(shí),Lifecycle 也規(guī)定,只有當(dāng)所有產(chǎn)出物都匹配有一個(gè)對(duì)應(yīng)的所需物時(shí),這些 Buildpacks 才能組合成一個(gè) Builder。
Analysis
Buildpacks 在運(yùn)行中會(huì)創(chuàng)建一些目錄,在 Lifecycle 中這些目錄被稱為 layer。那么為了這些 layer 中,有一些是可以作為緩存提供給下一個(gè) Buildpacks 使用的,有一些則是需要在應(yīng)用運(yùn)行時(shí)起作用的,還有的則是需要被清理掉。怎么才能更靈活地控制這些 layer ?
Lifecycle 提供了三個(gè)開關(guān)參數(shù),用于表示每一個(gè) layer 期望的處理方式:
launch 表示這個(gè) layer 是否將在應(yīng)用運(yùn)行時(shí)起作用。 build 表示這個(gè) layer 是否將在后續(xù)的構(gòu)建過程中被訪問。 cache 則表示這個(gè) layer 是否將作為緩存。
之后,Lifecycle 再根據(jù)一個(gè)關(guān)系矩陣來判斷 layer 的最終歸宿。我們也可以簡(jiǎn)單的理解為,Analysis 階段為構(gòu)建、應(yīng)用運(yùn)行提供了緩存。

Build
Build 階段會(huì)利用 Detect 階段產(chǎn)出的 build plan,以及環(huán)境中的元數(shù)據(jù)信息,配合保留至本階段的 layers,對(duì)應(yīng)用源碼執(zhí)行 Buildpacks 中的構(gòu)建邏輯。最終生成可運(yùn)行的應(yīng)用工件。

Export
Export 階段比較好理解,在完成了上述構(gòu)建之后,我們需要將最后的構(gòu)建結(jié)果產(chǎn)出為一個(gè) OCI 標(biāo)準(zhǔn)鏡像,這樣一來,這個(gè) App 工件就可以運(yùn)行在任何兼容 OCI 標(biāo)準(zhǔn)的集群中。

Rebase
在 CNB 的設(shè)計(jì)中,最后 app 工件實(shí)際是運(yùn)行在 stack 的 run image 之上的??梢岳斫鉃?run image 以上的工件是一個(gè)整體,它與 run image 以 ABI(application binary interface) 的形式對(duì)接,這就使得這個(gè)工件可以靈活切換到另一個(gè) run image 上。
這個(gè)動(dòng)作其實(shí)也是 Lifecycle 的一部分,叫做 rebase。在構(gòu)建鏡像的過程中也有一次 rebase,發(fā)生在 app 工件由 build image 切換到 run image 上。

這種機(jī)制也是 CNB 對(duì)比 Dockerfile 最具優(yōu)勢(shì)的地方。比如在一個(gè)大型的生產(chǎn)環(huán)境中,如果容器鏡像的 OS 層出現(xiàn)問題,需要更換鏡像的 OS 層,那么針對(duì)不同類型的應(yīng)用鏡像就需要重寫他們的 dockerfile 并驗(yàn)證新的 dockerfile 是否可行,以及新增加的層與已存在的層之間是否有沖突,等等。而使用 CNB 只需要做一次 rebase 即可,簡(jiǎn)化了大規(guī)模生產(chǎn)中鏡像的升級(jí)工作。
以上就是關(guān)于 CNB 構(gòu)建鏡像的流程分析,總結(jié)來說:
Buildpacks 是最小構(gòu)建單元,執(zhí)行具體的構(gòu)建操作; Lifecycle 是 CNB 提供的鏡像構(gòu)建生命周期接口; Builder 是若干 Buildpacks 加上 Lifecycle 以及 stack 形成的具備特定構(gòu)建目的的構(gòu)建器。

再精減一下:
build image + run image = stack stack(build image) + buildpacks + lifecycle = builder stack(run image) + app artifacts = app
那么現(xiàn)在問題來了,這個(gè)工具怎么使用呢?
Platform
這時(shí)候就需要一個(gè) Platform,Platform 其實(shí)是 Lifecycle 的執(zhí)行者。它的作用是將 Builder 作用于給定的源代碼上,完成 Lifecycle 的指令。

在這個(gè)過程中,Builder 會(huì)將源代碼構(gòu)建為 app,這個(gè)時(shí)候 app 是在 build image 中的。這個(gè)時(shí)候根據(jù) Lifecycle 中的 rebase 接口,底層邏輯是用 ABI(application binary interface)[10] 將 app 工件從 build image 轉(zhuǎn)換到 run image 上。這就是最后的 OCI 鏡像。
常用的 Platform 有 Tekton 和 CNB 的 Pack[11]。接下來我們將使用 Pack 來體驗(yàn)如何使用 Buildpacks 構(gòu)建鏡像。
安裝 Pack CLI 工具
目前 Pack CLI 支持 Linux、MacOS 和 Windows 平臺(tái),以 Ubuntu 為例,安裝命令如下:
$?sudo?add-apt-repository?ppa:cncf-buildpacks/pack-cli
$?sudo?apt-get?update
$?sudo?apt-get?install?pack-cli
查看版本:
$?pack?version
0.22.0+git-26d8c5c.build-2970
注意:在使用 Pack 之前,需要先安裝并運(yùn)行 Docker。
目前 Pack CLI 只支持 Docker,不支持其他容器運(yùn)行時(shí)(比如 Containerd 等)。但 Podman 可以通過一些 hack 來變相支持,以 Ubuntu 為例,大概步驟如下:
先安裝 podman。
$?.?/etc/os-release
$?echo?"deb?https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/?/"?|?sudo?tee?/etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
$?curl?-L?"https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/xUbuntu_${VERSION_ID}/Release.key"?|?sudo?apt-key?add?-
$?sudo?apt-get?update
$?sudo?apt-get?-y?upgrade
$?sudo?apt-get?-y?install?podman
然后啟用 Podman Socket。
$?systemctl?enable?--user?podman.socket
$?systemctl?start?--user?podman.socket
指定 DOCKER_HOST 環(huán)境變量。
$?export?DOCKER_HOST="unix://$(podman?info?-f?"{{.Host.RemoteSocket.Path}}")"
最終就可以實(shí)現(xiàn)在 Podman 容器運(yùn)行時(shí)中使用 Pack 來構(gòu)建鏡像。詳細(xì)配置步驟可參考 Buildpacks 官方文檔[12]。
使用 Pack 構(gòu)建 OCI 鏡像
安裝完 Pack 之后,我們可以通過 CNB 官方提供的 samples[13] 加深對(duì) Buildpacks 原理的理解。這是一個(gè) Java 示例,構(gòu)建過程中無需安裝 JDK、運(yùn)行 Maven 或其他構(gòu)建環(huán)境,Buildpacks 會(huì)為我們處理好這些。
首先克隆示例倉(cāng)庫(kù):
$?git?clone?https://github.com/buildpacks/samples.git
后面我們將使用 bionic 這個(gè) Builder 來構(gòu)建鏡像,先來看下該 Builder 的配置:
$ cat samples/builders/bionic/builder.toml
# Buildpacks to include in builder
[[buildpacks]]
id = "samples/java-maven"
version = "0.0.1"
uri = "../../buildpacks/java-maven"
[[buildpacks]]
id = "samples/kotlin-gradle"
version = "0.0.1"
uri = "../../buildpacks/kotlin-gradle"
[[buildpacks]]
id = "samples/ruby-bundler"
version = "0.0.1"
uri = "../../buildpacks/ruby-bundler"
[[buildpacks]]
uri = "docker://cnbs/sample-package:hello-universe"
# Order used for detection
[[order]]
[[order.group]]
id = "samples/java-maven"
version = "0.0.1"
[[order]]
[[order.group]]
id = "samples/kotlin-gradle"
version = "0.0.1"
[[order]]
[[order.group]]
id = "samples/ruby-bundler"
version = "0.0.1"
[[order]]
[[order.group]]
id = "samples/hello-universe"
version = "0.0.1"
# Stack that will be used by the builder
[stack]
id = "io.buildpacks.samples.stacks.bionic"
run-image = "cnbs/sample-stack-run:bionic"
build-image = "cnbs/sample-stack-build:bionic"
builder.toml 文件中完成了對(duì) Builder 的定義,配置結(jié)構(gòu)可以劃分為 3 個(gè)部分:
[[buildpacks]] 語(yǔ)法標(biāo)識(shí)用于定義 Builder 所包含的 Buildpacks。 [[order]] 用于定義 Builder 所包含的 Buildpacks 的執(zhí)行順序。 [[stack]] 用于定義 Builder 將運(yùn)行在哪個(gè)基礎(chǔ)環(huán)境之上。
我們可以使用這個(gè) builder.toml 來構(gòu)建自己的 builder 鏡像:
$?cd?samples/builders/bionic
$?pack?builder?create?cnbs/sample-builder:bionic?--config?builder.toml
284055322776:?Already?exists
5b7c18d5e17c:?Already?exists
8a0af02bbad1:?Already?exists
0aa0fb9222a5:?Download?complete
3d56f4bc2c9a:?Already?exists
5b7c18d5e17c:?Already?exists
284055322776:?Already?exists
8a0af02bbad1:?Already?exists
a967314b5694:?Already?exists
a00d148009e5:?Already?exists
dbb2c49b44e3:?Download?complete
53a52c7f9926:?Download?complete
0cceee8a8cb0:?Download?complete
c238db6a02a5:?Download?complete
e925caa83f18:?Download?complete
Successfully?created?builder?image?cnbs/sample-builder:bionic
Tip:?Run?pack?build??--builder?cnbs/sample-builder:bionic?to?use?this?builder
接著,進(jìn)入 samples/apps 目錄,使用 pack 工具和 builder 鏡像,完成應(yīng)用的構(gòu)建。當(dāng)構(gòu)建成功后,會(huì)產(chǎn)出一個(gè)名為 sample-app 的 OCI 鏡像。
$?cd?../..
$?pack?build?--path?apps/java-maven?--builder?cnbs/sample-builder:bionic?sample-app
最后使用 Docker 運(yùn)行這個(gè) sample-app 鏡像:
$?docker?run?-it?-p?8080:8080?sample-app
訪問 http://localhost:8080,如果一切正常,你可以在瀏覽器中看見如下的界面:

現(xiàn)在我們?cè)賮碛^察一下之前構(gòu)建的鏡像:
$?docker?images
REPOSITORY???????????????????????????????TAG??????????????IMAGE?ID???????CREATED????????SIZE
cnbs/sample-package??????????????????????hello-universe???e925caa83f18???42?years?ago???4.65kB
sample-app???????????????????????????????latest???????????7867e21a60cd???42?years?ago???300MB
cnbs/sample-builder??????????????????????bionic???????????83509780fa67???42?years?ago???181MB
buildpacksio/lifecycle???????????????????0.13.1???????????76412e6be4e1???42?years?ago???16.4MB
鏡像的創(chuàng)建時(shí)間竟然都是固定的時(shí)間戳:42 years ago。這是為什么呢?如果時(shí)間戳不固定,每次構(gòu)建鏡像的 hash 值都是不同的,一旦 hash 值不一樣,就不太容易判斷鏡像的內(nèi)容是否相同了。使用固定的時(shí)間戳,就可以重復(fù)利用之前的構(gòu)建過程中創(chuàng)建的 layers。
總結(jié)
Cloud Native Buildpacks 代表了現(xiàn)代軟件開發(fā)的一個(gè)重大進(jìn)步,在大部分場(chǎng)景下相對(duì)于 Dockerfile 的好處是立桿見影的。雖然大型企業(yè)需要投入精力重新調(diào)整 CI/CD 流程或編寫自定義 Builder,但從長(zhǎng)遠(yuǎn)來看可以節(jié)省大量的時(shí)間和維護(hù)成本。
本文介紹了 Cloud Native Buildpacks(CNB) 的起源以及相對(duì)于其他工具的優(yōu)勢(shì),并詳細(xì)闡述了 CNB 的工作原理,最后通過一個(gè)簡(jiǎn)單的示例來體驗(yàn)如何使用 CNB 構(gòu)建鏡像。后續(xù)的文章將會(huì)介紹如何創(chuàng)建自定義的 Builder、Buildpack、Stack,以及函數(shù)計(jì)算平臺(tái)(例如,OpenFunction[14]、Google Cloud Functions)如何利用 CNB 提供的 S2I 能力,實(shí)現(xiàn)從用戶的函數(shù)代碼到最終應(yīng)用的轉(zhuǎn)換過程。
引用鏈接
Cloud Native Buildpacks: https://buildpacks.io/
[2]開放容器倡議(OCI): https://opencontainers.org/
[3]OCI 運(yùn)行時(shí)標(biāo)準(zhǔn): https://github.com/opencontainers/runtime-spec
[4]Cloud Native Buildpacks(CNB): https://buildpacks.io/
[5]投票決定將 CNB 從沙箱項(xiàng)目晉升為孵化項(xiàng)目: https://www.cncf.io/blog/2020/11/18/toc-approves-cloud-native-buildpacks-from-sandbox-to-incubation/
[6]跨鏡像倉(cāng)庫(kù)的 blob 掛載和鏡像層級(jí) rebasing: https://docs.docker.com/registry/spec/api/
[7]Stack: https://buildpacks.io/docs/concepts/components/stack
[8]caching: https://buildpacks.io/docs/app-developer-guide/using-cache-image/
[9]rebasing: https://buildpacks.io/docs/concepts/operations/rebase/
[10]ABI(application binary interface): https://en.wikipedia.org/wiki/Application_binary_interface
[11]Pack: https://buildpacks.io/docs/tools/pack/
[12]Buildpacks 官方文檔: https://buildpacks.io/docs/app-developer-guide/building-on-podman/
[13]samples: https://github.com/buildpacks/samples
[14]OpenFunction: https://github.com/OpenFunction/OpenFunction/
關(guān)于?KubeSphere
KubeSphere (https://kubesphere.io)是在 Kubernetes 之上構(gòu)建的開源容器混合云,提供全棧的 IT 自動(dòng)化運(yùn)維的能力,簡(jiǎn)化企業(yè)的 DevOps 工作流。
KubeSphere?已被?Aqara?智能家居、愛立信、本來生活、東軟、華云、新浪、三一重工、華夏銀行、四川航空、國(guó)藥集團(tuán)、微眾銀行、杭州數(shù)跑科技、紫金保險(xiǎn)、去哪兒網(wǎng)、中通、中國(guó)人民銀行、中國(guó)銀行、中國(guó)人保壽險(xiǎn)、中國(guó)太平保險(xiǎn)、中國(guó)移動(dòng)、中國(guó)電信、天翼云、中移金科、Radore、ZaloPay?等海內(nèi)外數(shù)千家企業(yè)采用。KubeSphere 提供了開發(fā)者友好的向?qū)讲僮鹘缑婧拓S富的企業(yè)級(jí)功能,包括?Kubernetes?多云與多集群管理、DevOps?(CI/CD)、應(yīng)用生命周期管理、邊緣計(jì)算、微服務(wù)治理?(Service?Mesh)、多租戶管理、可觀測(cè)性、存儲(chǔ)與網(wǎng)絡(luò)管理、GPU?support?等功能,幫助企業(yè)快速構(gòu)建一個(gè)強(qiáng)大和功能豐富的容器云平臺(tái)。
