容器化技術的興起,讓 Buildah 成為建構客製化容器映象的利器。不同於 Docker 的單體式架構,Buildah 以更細緻的粒度控制容器映象的每個構建步驟,賦予開發者更大的彈性。這對於追求效能和安全性最佳化的應用程式來說至關重要,尤其在微服務架構和雲原生應用程式開發中,Buildah 的優勢更加明顯。選擇合適的容器基礎映像是確保容器安全性和效能的關鍵。通用基礎映像(UBI)根據 Red Hat Enterprise Linux,兼具穩定性、安全性與相容性,是企業級應用程式的理想選擇。透過 UBI,開發者可以更輕鬆地建構和佈署容器化應用程式,同時降低安全風險。

在實際應用中,Buildah 提供了豐富的指令和 API,方便開發者將其整合到現有的 CI/CD 流程中。例如,可以利用 Buildah 的 FROM 指令指定基礎映像,COPY 指令複製應用程式碼,RUN 指令執行建置指令,最後使用 COMMIT 指令提交變更,生成最終的容器映象。此外,Buildah 還支援多階段建構,可以有效減小映象體積,提升佈署效率。這對於需要頻繁迭代和佈署的應用程式來說尤為重要。

瞭解開放容器倡議(OCI)的映像格式規範,對於理解容器技術的底層原理至關重要。OCI 規範定義了容器映象的標準格式,確保了不同容器引擎之間的互通性。這意味著使用 Buildah 建構的容器映象,可以無縫地在 Docker、Podman 等其他相容 OCI 規範的容器引擎上執行。這為開發者提供了更大的選擇空間,也促進了容器生態的繁榮發展。

Buildah 的應用場景非常廣泛,例如可以結合 Quarkus 建構原生可執行檔,或是與 Rust 語言的 Buildah wrapper 整合,簡化建置流程。這些應用案例都展現了 Buildah 的靈活性和強大功能。透過 Buildah,開發者可以更精確地控制容器映象的建構過程,並根據專案需求進行客製化組態,最終開發更精簡、高效的容器化應用程式。

玄貓解析:如何利用 Buildah 開發客製化容器映象?

在容器化應用程式的浪潮下,Buildah 提供了強大的工具,讓開發者能夠以程式化的方式建立容器映象。本文將分享如何整合 Buildah 到現有的應用程式建置流程中,並探討幾個實際案例,展示 Buildah 的靈活性和應用場景。

整合 Buildah 到現有建置流程:實戰演練

假設我們有一個 Node.js 應用程式,需要將其封裝成容器映象。首先,我們需要將包含應用程式的 JavaScript 檔案加入到容器映象中。

err = builder.Add("/home/node/", false, buildah.AddAndCopyOptions{}, "script.js")

這裡,我們假設 JavaScript 主檔案 script.js 位於 Go 模組旁邊,並將其複製到 /home/node 目錄下。這個目錄是基礎容器映象預期找到資料的預設路徑。

讓我們來看看這個簡單的 JavaScript 程式:

var http = require("http");
http.createServer(function(request, response) {
  response.writeHead(200, {"Content-Type": "text/plain"});
  response.write("Hello Podman and Buildah friends. This page is provided to you through a container running Node.js version: ");
  response.write(process.version);
  response.end();
}).listen(8080);

這段程式碼使用 HTTP 函式庫監聽 8080 連線埠的請求,並回覆包含 Node.js 版本的歡迎訊息。

內容解密

  • require("http"): 引入 Node.js 的 HTTP 模組,用於建立 HTTP 伺服器。
  • http.createServer(function(request, response) { ... }): 建立一個新的 HTTP 伺服器,並定義處理請求的回呼函式。
  • response.writeHead(200, {"Content-Type": "text/plain"}): 設定 HTTP 回應的標頭,指定狀態碼為 200 (OK) 與內容型別為純文字。
  • response.write(...): 將資料寫入 HTTP 回應的主體。
  • response.end(): 結束 HTTP 回應。
  • .listen(8080): 讓伺服器監聽 8080 連線埠的請求。

接下來,我們設定容器映象的預設執行命令:

builder.SetCmd([]string{"node", "/home/node/script.js"})

這會指示容器在啟動時執行 Node.js 執行環境,並執行我們剛加入的 JavaScript 程式。

為了提交變更,我們需要取得映象參考,並定義 Builder 將建立的容器映象名稱:

imageRef, err := is.Transport.ParseStoreReference(buildStore, "podmanbook/nodejs-welcome")

現在,我們可以提交變更並呼叫 Builder 的 Commit 函式:

imageId, _, _, err := builder.Commit(context.TODO(), imageRef, define.CommitOptions{})
fmt.Printf("Image built! %s\n", imageId)

這會指示 Builder 提交變更,並印出映象的參考 ID。

實際執行與驗證

現在,讓我們來執行剛剛建立的容器映象:

[builder]$ go run custombuilder.go
Image built!
e60fa98051522a51f4585e46829ad6a18df704dde774634dbc010baae4404849
[builder]$ podman run -dt -p 8080:8080/tcp podmanbook/nodejs-welcome:latest
747805c1b59558a70c4a2f1a1d258913cae5ffc08cc026c74ad3ac21aab18974
[builder]$ curl localhost:8080
Hello Podman and Buildah friends. This page is provided to you through a container running Node.js version: v12.22.7

我們使用 podman run 命令以分離模式執行容器,並將容器的 8080 連線埠發布到主機系統。最後,我們使用 curl 命令來請求並印出 JavaScript 程式提供的 HTTP 回應。

內容解密

  • podman run -dt -p 8080:8080/tcp podmanbook/nodejs-welcome:latest: 使用 Podman 執行名為 podmanbook/nodejs-welcome:latest 的容器映象。
    • -d: 以分離模式執行容器,使其在背景執行。
    • -t: 分配一個新的偽終端機。
    • -p 8080:8080/tcp: 將容器的 8080 連線埠對映到主機的 8080 連線埠,允許從主機存取容器內的服務。
  • curl localhost:8080: 使用 curl 命令向本機的 8080 連線埠傳送 HTTP 請求,並顯示伺服器的回應。

Buildah 的更多應用場景

Buildah 的靈活性使其能夠支援各種客製化建置流程。以下是一些實際案例:

Quarkus 原生可執行檔容器化

Quarkus 是一個 Kubernetes 原生的 Java 堆積疊,它利用 OpenJDK 和 GraalVM 專案。GraalVM 是一個 Java 虛擬機器,具有許多特殊功能,例如編譯 Java 應用程式以實作快速啟動和低記憶體佔用。

在 Quarkus 的檔案中,我們可以找到如何使用 Maven wrapper 和特殊選項來建置 Quarkus 原生可執行檔,並將其封裝到容器映象中:

$ ./mvnw package -Pnative -Dquarkus.native.container-build=true -Dquarkus.native.container-runtime=podman

這個命令會呼叫 Podman 建置,以建立包含預先設定環境和二進位應用程式的容器映象。

Rust 語言的 Buildah Wrapper

另一個有趣的例子是 Rust 程式語言的 Buildah wrapper。Rust 是一種類別似 C++ 的程式語言,專為效能和安全平行而設計。這個 Buildah wrapper 利用 Rust 的套件管理器 Cargo 來下載依賴項,並將其編譯成可發布的套件。

玄貓結語

Buildah 是一個非常靈活的工具,其函式庫可以支援各種不同的客製化建置情境。透過程式化的方式,開發者可以精確控制容器映象的建置過程,並將其整合到現有的開發流程中。從 Quarkus 到 Rust,Buildah 的應用範圍非常廣泛,為容器化應用程式的開發提供了強大的支援。

為何我放棄傳統ORM:擁抱Buildah與容器化建構的技術轉型

在過去的專案中,我經常使用ORM(物件關係對映)來簡化資料函式庫操作。但隨著專案規模擴大,ORM的效能瓶頸日益明顯。最近,我開始探索Buildah這一容器建構工具,並發現它在提升應用程式建構效率和可移植性方面有巨大潛力。本文將分享我如何利用Buildah進行容器化建構,以及為何我認為這種方法在某些場景下優於傳統的應用程式建構流程。

從多階段建構到客製化建構:Buildah 的進階應用

在之前的專案中,我們已經學會如何使用Buildah來建立多階段容器映像。這種方法允許我們使用不同的FROM指令,在多個階段中構建映像,並從先前的階段取得內容。

容器化建構的需求場景

有許多使用案例表明需要容器化的建構。目前,最常見的採用場景之一是在 Kubernetes 叢集上執行的應用程式建構工作流程。因此,我們將探討容器化 Buildah 的細節。

整合 Buildah 以建立客製化建構器

最後,我們透過許多有趣的範例學習如何整合 Buildah 以為容器映像建立客製化建構器。正如我們在本章中所看到的,使用 Podman 生態系統工具實際建構容器映像有多種選項和方法,大多數時候,我們通常從基礎映像開始,以客製化和擴充套件先前的作業系統層以適應我們的使用案例。

Buildah 與現有應用程式建構流程的整合

Buildah 的整合非常簡單。以下程式碼展示瞭如何使用 Buildah 建立一個 Nginx 容器:

$ cd examples/
$ cargo run --example nginx
$ podman run --rm -it -p 8080:80 nginx_rust

第一行指令選擇 examples 目錄,然後執行一段簡單的程式碼來建立容器。第二行指令測試 Buildah wrapper 剛透過 Buildah 建立的容器映像。

以下是 nginx.rs 檔案中的 Rust 程式碼:

use buildah_rs::container::Container;

fn main() {
    let mut container = Container::from("nginx:1.21");
    container.copy("html", "/usr/share/nginx/html").unwrap();
    container.commit("nginx_rust").unwrap();
}

這段程式碼匯入 Buildah wrapper 函式庫,從 nginx:1.21 建立一個容器映像,然後將本地 html 目錄複製到容器映像的目的地路徑。

內容解密

  • use buildah_rs::container::Container;:匯入 Buildah wrapper 函式庫中的 Container 模組,用於操作容器。
  • fn main() { ... }:Rust 程式的進入點。
  • let mut container = Container::from("nginx:1.21");:從 Nginx 1.21 映像建立一個新的容器例項。mut 關鍵字表示 container 變數是可變的。
  • container.copy("html", "/usr/share/nginx/html").unwrap();:將本地的 html 目錄複製到容器內的 /usr/share/nginx/html 目錄。.unwrap() 用於處理 Result 型別,如果複製失敗會觸發 panic。
  • container.commit("nginx_rust").unwrap();:將容器提交為一個新的映像,命名為 nginx_rust。同樣,.unwrap() 用於處理可能發生的錯誤。

更多資訊

如需深入瞭解此範例,請參考 https://github.com/Dennis-Krasnov/Buildah-Rust

容器基礎映像的選擇:開發安全可靠的根本

選擇合適的容器基礎映像是容器化旅程中的重要任務。容器基礎映像是系統服務、應用程式或程式碼所依賴的底層作業系統層。因此,我們應該選擇一個符合安全性和更新最佳實務的映像。

容器映像的來源

在探討容器管理之後,我發現有時可用的服務、其組態,甚至應用程式版本都不是專案所需的。然後,我介紹了 Buildah 及其用於建構客製化容器映像的功能。在本文中,我們將討論另一個在社群和企業專案中經常被問到的重要主題:容器基礎映像的選擇。

可信任的容器映像來源

選擇容器映像時,信任來源至關重要。玄貓建議使用經過驗證和評價良好的來源,以確保映像的安全性和可靠性。

通用基礎映像 (Universal Base Image, UBI) 簡介

通用基礎映像(UBI)是一種由 Red Hat 提供的免費、可重新發布與開發人員友好的基礎映像。UBI 映像根據 Red Hat Enterprise Linux (RHEL),但可以免費使用和分發,無需訂閱。這使得 UBI 成為建構容器化應用程式的理想選擇,特別是對於那些需要在 RHEL 環境中佈署的應用程式。

開放容器倡議 (OCI) 映像格式

正如我們在第一章「容器技術簡介」中所描述的,Docker 在 2013 年被引入容器領域,並迅速普及。

在高層次上,Docker 團隊引入了容器映像和容器登入檔的概念,這是一個改變遊戲規則的舉動。另一個重要的步驟是能夠從 Docker 中提取 containerd 專案並將它們捐贈給雲原生計算基金會 (CNCF)。這激勵了開源社群開始認真研究可以注入到 Kubernetes 等協調層中的容器引擎。

同樣,在 2015 年,Docker 在許多其他公司(Red Hat、AWS、Google、Microsoft、IBM 等)的幫助下,在 Linux 基金會的保護下啟動了開放容器倡議 (OCI)。

這些貢獻者開發了執行階段規範 (runtime-spec) 和映像規範 (image-spec),以描述未來應如何建立新容器引擎的 API 和架構。

經過幾個月的工作,OCI 團隊發布了其第一個符合 OCI 規範的容器引擎實作;該專案被命名為 runc

詳細研究容器映像規範並回顧第二章「比較 Podman 和 Docker」中介紹的實務背後的一些理論是值得的。

該規範定義了一個 OCI 容器映像,它由以下內容組成:

  • Manifest:包含映像的內容和相依性的中繼資料。這還包括識別一個或多個檔案系統存檔的能力,這些檔案系統存檔將被解壓縮以獲得最終的可執行檔案系統。

玄貓對容器技術的深度思考

從我多年的開發經驗來看,容器技術的發展趨勢是不可逆轉的。Buildah 作為 Podman 生態系統中的重要一員,為我們提供了更靈活、更高效的容器建構方式。透過 Buildah,我們可以更好地控制容器映像的建構過程,並將其與現有的應用程式建構流程整合。

在選擇容器基礎映像時,安全性和可靠性是最重要的考量因素。通用基礎映像(UBI)是一個值得推薦的選擇,它不僅免費與易於使用,還能提供良好的安全保障。

在未來,隨著容器技術的普及,我相信 Buildah 和 UBI 將在容器化應用程式的開發和佈署中扮演越來越重要的角色。