利用Makisu構建容器鏡像

雲棲號資訊:【點擊查看更多行業資訊
在這裏您可以找到不同行業的第一手的上雲資訊,還在等什麼,快來!


本系列文章深入研究了容器鏡像構建的最新技術。我們已經介紹了Podman和Buildah、Img、Kaniko,而這次輪到Makisu了。

Makisu是另一個開源鏡像構建工具,由Uber的工程團隊構思而成。像許多其他開源項目一樣,Makisu也是基於其他類似技術的不足而開發的。 Makisu尤其專注於優化鏡像構建時間和大小。

使用Makisu

類似Kaniko,Makisu不會調用容器並依據Dockerfile指令在容器中構建鏡像。它既可以作爲獨立的二進制文件在本地運行,也可以作爲沙箱運行在容器內。但是,由於它無法執行RUN Dockerfile指令,因此它作爲獨立二進制文件的用途受到限制。當然,你也不希望Makisu通過RUN指令更改主機的本地文件系統內容!

實際上Makisu不允許更改本地文件;你需要指定標誌--modifyfs = true,以允許使用命令對文件系統進行更改。但請注意,如果使用--modifyfs = true運行獨立的Makisu二進制文件,最終將刪除主機的許多rootfs。 Makisu被設計爲在容器中運行,在容器中更改文件系統內容是安全的。

實際上用於執行構建的Makisu本身的容器鏡像很少。它是基於基本圖像指令(scratch base image directive)構建的,僅包含Makisu二進制文件和根CA證書的文件。需要使用卷將構建上下文(包括Dockerfile)提供給容器。

Makisu提取Dockerfile中定義的基本鏡像,並將其文件系統提取到其容器內。它還將此文件系統的副本存儲在內存中。隨後的構建步驟針對該文件系統的內容運行,然後對其進行掃描以查找更改。任何更改也會反映在“內存”的副本中,並創建一個包含更改的新“差異層”。 “差異層”層緩存在目錄中,以供將來的版本使用,前提是用於存儲的卷已經被掛載。

Dockerfile中定義的構建步驟以這種方式執行到完成,然後Makisu將構建的鏡像推送到容器鏡像倉庫(如果已指定)。如果將Docker用作Makisu的容器運行時,則可以使用以下命令調用構建容器:

$ docker run --rm \
  -v $(pwd):/makisu-context \
  -v /tmp/makisu-storage:/makisu-storage \
  gcr.io/makisu-project/makisu:v0.1.12 build \
      --tag=mycorp/my-app:1d03df1 \
      --push=quay.io \
      --modifyfs=true \
      /makisu-context

如果你閱讀了本系列的上一篇文章,你將已經得出結論,如Kaniko一樣,Makisu將採用幾乎相同的方法來構建鏡像。你可以執行構建步驟而無需Docker守護程序,也無需運行嵌套容器所需的特權賬號。但是 Makisu的突出之處在於其構建緩存實現的方法。

緩存

一旦決定放棄Docker守護進程構建鏡像,你將失去其固有的緩存功能。 Docker守護程序提供的構建步驟緩存可能不像許多人所希望的那樣具有豐富的功能,但是緩存是鏡像構建的基本功能。通過複用以前執行過的相同構建步驟所生成的內容,它有助於優化構建時間。對於Uber來說,這是促使他們決定創建替代容器鏡像構建工具的重要因素之一。那麼,Makisu通過緩存功能提供了什麼?

分佈式緩存

在Kubernetes設置中,包含構建容器的Pod在理論上可以存在於集羣內的任何節點上。

這帶來了一個問題:構建容器如何才能利用先前構建迭代生成的緩存鏡像層?

我們可以嘗試迫使Pod落在執行了先前構建迭代的節點上,但這會影響調度程序的作用和目的。相反,Makisu利用分佈式緩存來解決此問題。

首先,Makisu提供了Dockerfile指令序列和diff層摘要之間的本地映射。這些映射保存在鍵值存儲中,鍵值存儲可以是文件,分佈式Redis緩存或基於HTTP的通用緩存。重要的是緩存是分佈式的,因此可以由任何有權訪問緩存的Makisu構建容器引用。

緩存中的映射使Makisu能夠確定是否需要執行現有的構建步驟,或者是否可以使用現有層的內容。如果在緩存中找到匹配項,則可以從Makisu管理的本地存儲中解壓縮該圖層(如果它存在於本地存儲中),或者從鏡像倉庫中提取該圖層(如果已推送先前的構建)。

緩存中的密鑰是從Dockerfile指令生成的,用於構建步驟並與先前構建步驟相關聯。關聯值是先前生成的鏡像層內容的哈希值。如果構建步驟指令序列與緩存中的現有鍵匹配,則Makisu將使用摘要(作爲鍵值保存)來定位diff層。

緩存具有可配置的生存時間(TTL),以確保緩存的圖層不會過時。

選擇性提交(Optional Commits)

在使用Docker守護程序進行鏡像構建期間,將爲新生構建或有更改內容的每個構建步驟生成diff層。這導致創建images鏡像非常臃腫。有時,可以通過合理地使用構建步驟在控制這些中間層,或將大量命令組合到一個Dockerfile指令中來控制這些中間層的數量。 Makisu使用自己獨特的技術來緩解此問題。

Makisu的Dockerfile指令解析器引入了一個指令,該指令控制在構建過程中何時提交差異層。語法#!COMMIT註釋的任何指令都被解析器解釋爲生成新層。那些沒有該註釋的將不會生成新的層。

FROM alpine

RUN apk add --no-cache wget

RUN apk add --no-cache curl #!COMMIT
<SNIP>

在上面的示例中,安裝wget的RUN指令未提交爲新層,而安裝curl的則被提交。它創建了一個圖層,其中包含自上一次提交以來或從構建階段開始以來的所有新內容。

當爲Makisu指定--commit = explicit標誌時,顯示緩存將爲構建打開。沒有它,#!COMMIT語法將被視爲註釋,就像Docker守護程序的解析器一樣。這樣,用於Makisu顯式緩存的Dockerfile便與Docker守護程序保持兼容。

顯式提交可以爲鏡像構建提供更大的靈活性;創建的層數更少,通常會使得圖像更小,並改善了Dockerfile的可維護性。

結論

Makisu是一種非常強大的容器鏡像構建工具,它是出於解決大型生產環境中存在的缺陷而產生的。它的方法消除了在容器構建期間對提升特權的需求(儘管構建是作爲root用戶執行的),並且它具有一種新穎的方法來構建緩存實現。

它無法解決Dockerfile指令順序解析中固有的構建效率低下的問題。而且,構建執行並不總是能忠實地反映Docker鏡像構建的預期行爲。但是,Makisu來自著名的工程師團隊,是新型容器鏡像構建工具的又一個重要補充。

【雲棲號在線課堂】每天都有產品技術專家分享!
課程地址:https://yqh.aliyun.com/live

立即加入社羣,與專家面對面,及時瞭解課程最新動態!
【雲棲號在線課堂 社羣】https://c.tb.cn/F3.Z8gvnK

原文發佈時間:2020-07-09
本文作者:吳世曦
本文來自:“dockone”,瞭解相關信息可以關注“dockone”

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章