返回文章列表

Buildah 容器映像檔建置

本文探討使用 Buildah 建立容器映像檔的技巧,涵蓋從零開始建置、Dockerfile 的使用、映像檔層級管理以及最佳實務。同時比較 Buildah 與 Podman 在映像檔建置方面的差異,並提供實用的程式碼範例和指令說明,幫助讀者理解並掌握 Buildah 的核心功能。

容器技術 DevOps

理解容器映像檔的建置流程對於容器技術的應用至關重要。本文從 Podman 的基本用法出發,逐步介紹 Dockerfile 的語法和指令,並探討 Buildah 的進階功能,讓讀者能更有效率地建置和管理容器映像檔。 Buildah 提供了更細緻的操作,讓開發者可以控制映像檔的每個層級,並透過指令碼自動化建置流程,提升開發效率。相較於 Dockerfile 的宣告式方法,Buildah 更具彈性,適合處理複雜的建置場景。

使用 Buildah 從零開始建立容器

容器的最大魅力在於能夠將應用程式封裝到不可變的映像檔中,並在不同系統上無縫執行。本章將探討如何使用不同技術和工具建立映像檔,包括瞭解映像檔建立的底層原理以及如何從零開始建立映像檔。

技術需求

在開始本章之前,需要一台安裝了 Podman 的機器。書中的範例均在 Fedora 34 或更高版本的系統上執行,但讀者可以在自己選擇的作業系統上重現這些範例。

此外,對第 4 章「管理執行中的容器」中涵蓋的主題有基本的瞭解,將有助於輕鬆掌握 Open Container Initiative(OCI)映像檔的概念。

使用 Podman 進行基本映像檔建立

容器的 OCI 映像檔是一組不可變的層,按照複製時寫入(copy-on-write)的邏輯堆積疊在一起。當建立映像檔時,所有層都會按照特定的順序建立,然後推播到容器註冊中心,註冊中心將我們的層以 tar 為基礎的壓縮檔形式儲存,同時儲存額外的映像檔後設資料。

底層構建原理

容器映像檔可以透過不同的方式建立,但最常見的方法可能是根據 Dockerfile 的方法。Dockerfile 是一個純文字檔案,列出了在建立過程中要執行的動作。

隨著時間的推移,Dockerfile 成為了 OCI 映像檔建立的標準,並在許多使用案例中被採用。

重要注意事項 為了標準化和消除與品牌的關聯,還引入了 Containerfile。Containerfile 與 Dockerfile 具有相同的語法,並且原生支援 Podman。在本文中,我們將交替使用 Dockerfile 和 Containerfile 這兩個術語。

準備環境

在使用 Buildah 建立映像檔之前,我們需要準備好我們的環境。這包括安裝必要的工具和組態工作目錄。

選擇構建策略

在建立映像檔時,我們有多種策略可供選擇。我們可以從零開始建立映像檔,也可以根據現有的映像檔進行修改和擴充套件。

從零開始建立映像檔

從零開始建立映像檔需要對 OCI 映像檔的結構和內容有深入的瞭解。我們將學習如何使用 Buildah 從頭開始建立一個新的映像檔。

從 Dockerfile 建立映像檔

除了從零開始建立映像檔外,我們還可以使用 Dockerfile 或 Containerfile 來建立映像檔。這種方法更為常見,也更方便。本章將介紹如何使用 Dockerfile 建立映像檔。

使用 Buildah 建立容器映像檔

Buildah 是 Podman 的配套工具,專門用於建立容器映像檔。使用 Buildah,我們可以更靈活、更高效地建立和管理容器映像檔。

基本概念

在使用 Buildah 之前,我們需要了解一些基本概念,例如 OCI 映像檔的結構、層的概念等。

安裝與組態 Buildah

在使用 Buildah 之前,我們需要在系統上安裝並組態好 Buildah。這包括安裝 Buildah 軟體包和組態相關的環境變數。

# 在 Fedora 系統上安裝 Buildah
sudo dnf install -y buildah

詳細解說:

  1. sudo dnf install -y buildah:這條命令用於在 Fedora 系統上安裝 Buildah。其中,sudo 表示以管理員許可權執行命令,dnf install 是用於安裝軟體包的命令,-y 表示自動確認安裝,buildah 是要安裝的軟體包名稱。

使用 Buildah 建立映像檔

一旦安裝並組態好 Buildah,我們就可以開始使用它來建立容器映像檔了。本章將介紹如何使用 Buildah 從零開始建立一個新的映像檔,以及如何使用 Dockerfile 或 Containerfile 建立映像檔。

# 使用 Buildah 從零開始建立一個新的容器映像檔
buildah from scratch

詳細解說:

  1. buildah from scratch:這條命令用於從零開始建立一個新的容器映像檔。其中,buildah from 是用於建立新映像檔的命令,scratch 表示從零開始。

進一步閱讀

有關更多資訊,請參閱以下資源:

  • Containers Storage 專案頁面:https://github.com/containers/storage
  • Container Labeling:https://danwalsh.livejournal.com/81269.html
  • 為什麼應該為 Linux 容器使用多類別安全:https://www.redhat.com/en/blog/why-you-should-be-using-multi-category-security-your-linux-containers
  • Udica:生成 SELinux 策略:https://github.com/containers/udica
  • Overlay 原始碼:https://github.com/containers/storage/blob/main/drivers/overlay/overlay.go

使用 Podman 進行基礎映像檔建置

在探討 Dockerfile 的語法之前,我們先來瞭解 Dockerfile 的基本概念。Dockerfile 是一系列建置指令,建置工具會依序執行這些指令。以下是一個簡單的範例:

FROM docker.io/library/fedora
RUN dnf install -y httpd && dnf clean all -y
COPY index.html /var/www/html
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]

內容解密:

  1. FROM 指令:定義了基礎映像檔,本例中使用的是 Fedora。
  2. RUN 指令:在建置過程中執行特定動作,本例中是安裝 httpd 軟體包並清除快取。
  3. COPY 指令:將建置工作目錄中的檔案或目錄複製到映像檔中,本例中是將 index.html 複製到 /var/www/html
  4. CMD 指令:定義容器啟動時執行的命令,本例中是啟動 httpd 服務。

當執行 RUNCOPY 指令時,新的變更層會被快取在中間層中,這些中間層由暫時容器表示。這是 Docker 的原生功能,當沒有變更時,可以重複使用快取層,提高建置效率。

映像檔層與快取機制

並非所有的 Dockerfile 指令都會改變檔案系統,只有像 RUNCOPYADD 這樣的指令會建立新的映像檔層。其他指令,如 CMD,只會建立包含元資料的空層,不會影響最終的映像檔檔案系統。

為什麼要限制層數?

過多的層會影響圖形驅動程式的效能,因此建議減少 RUNCOPYADD 指令的使用。

檢查映像檔歷史

可以使用 podman inspect 命令檢查映像檔的歷史和每個層的操作。以下是一個範例輸出:

$ podman inspect myhttpd
[...省略輸出]
"History": [
    {
        "created": "2021-04-01T17:59:37.09884046Z",
        "created_by": "/bin/sh -c #(nop) LABEL maintainer=Clement Verna <[email protected]>",
        "empty_layer": true
    },
    {
        "created": "2021-10-24T21:27:18.783034844Z",
        "created_by": "/bin/sh -c dnf install -y httpd && dnf clean all -y",
        "comment": "FROM docker.io/library/fedora:latest"
    },
    {
        "created": "2021-10-24T21:27:21.095937071Z",
        "created_by": "/bin/sh -c #(nop) COPY file:78c6e1dcd6f819581b54094fd38a3fd8f170a2cb768101e533c964e04aacab2e in /var/www/html"
    },
    {
        "created": "2021-10-24T21:27:21.182063974Z",
        "created_by": "/bin/sh -c #(nop) CMD [\"/usr/sbin/httpd\", \"-DFOREGROUND\"]",
        "empty_layer": true
    }
]
[...省略輸出]

內容解密:

  1. 歷史記錄:顯示了映像檔建置過程中的每一步操作,包括時間戳記和執行的命令。
  2. 層的建立:可以看到 RUNCOPY 指令建立了新的層,而 CMD 指令只更新了元資料。

Dockerfile 和 Containerfile 指令

Dockerfile 和 Containerfile 共用相同的語法。以下是一些常見的指令:

  • FROM:定義基礎映像檔。
  • RUN:在暫時容器中執行命令。
  • COPY:將檔案或目錄複製到映像檔中。
  • ADD:將檔案、目錄或遠端 URL 複製到映像檔中,並支援自動解壓縮 tar 檔案。
  • ENTRYPOINT:定義容器啟動時執行的命令。

這些指令遵循相同的模式:INSTRUCTION arguments

最佳實踐

為了避免建立過多的層,建議將多個命令合併到一個 RUN 指令中,例如:

RUN dnf upgrade -y && \
    dnf install httpd -y && \
    dnf clean all -y

這種做法可以減少最終映像檔的層數,提高效能。

使用Podman進行基本映像檔建置

在深入瞭解如何使用Podman進行容器映像檔建置之前,我們需要先熟悉Dockerfile中的各種指令。這些指令對於定義映像檔的建置過程至關重要。

Dockerfile指令詳解

  • FROM: 指定基礎映像檔。如果本地不存在,Podman會自動從遠端倉函式庫提取。
  • RUN: 在映像檔建置過程中執行命令。可以是用於安裝軟體包、執行指令碼等。
  • ENTRYPOINT: 組態容器啟動時執行的命令。可以是可執行檔或指令碼。
  • CMD: 提供預設引數給ENTRYPOINT指令。可以是完整命令或引數列表。
  • LABEL: 為映像檔新增自定義標籤,用於在建置時或執行時作為中繼資料。
  • EXPOSE: 宣告容器內部程式監聽的埠。
  • ENV: 設定環境變數,在建置過程中和容器執行時都可用。
  • VOLUME: 指定容器執行時將建立的卷,用於持久化資料。
  • USER: 設定接下來RUN、CMD和ENTRYPOINT指令執行的使用者和群組。
  • WORKDIR: 設定建置過程中的工作目錄,該值在容器執行期間保留。
  • ONBUILD: 定義觸發命令,在映像檔作為父映像檔被用於新建置時執行。

使用Podman進行映像檔建置

Podman提供了與Docker相同的建置命令和語法,使得從Docker切換到Podman無需額外的學習成本。Podman的優勢在於它可以在無根模式下使用fork/exec模型建置容器。

簡單的Podman建置範例

考慮以下使用httpd Dockerfile的簡單建置範例:

$ podman build -t myhttpd .

建置步驟詳解

  1. FROM指令: 定義基礎映像檔,如果本地不存在則自動提取。

    FROM docker.io/library/fedora
    
  2. RUN指令: 安裝httpd套件並清理系統。

    RUN dnf install -y httpd && dnf clean all -y
    

    實際執行時,等同於"bash -c 'dnf install -y httpd && dnf clean all –y'"

  3. COPY指令: 將index.html檔案複製到預設的httpd檔案根目錄。

    COPY index.html /var/www/html
    
  4. CMD指令: 定義預設容器啟動命令,由於未設定ENTRYPOINT,因此實際執行的命令是"bash -c '/usr/sbin/httpd -DFOREGROUND'"

    CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
    

自定義Dockerfile範例

以下是一個自定義的Dockerfile,用於建置自定義的Web伺服器:

FROM docker.io/library/fedora

# 安裝必要的套件
RUN set -euo pipefail; \
    dnf upgrade -y; \
    dnf install httpd -y; \
    dnf clean all -y; \
    rm -rf /var/cache/dnf/*

# 為無根執行自定義Web伺服器組態
RUN set -euo pipefail; \
    sed -i 's|Listen 80|Listen 8080|' /etc/httpd/conf/httpd.conf; \
    # 其他自定義組態...

內容解密:

Dockerfile中的指令如何影響映像檔建置?

  1. FROM指令的作用:指定了基礎映像檔,決定了映像檔的初始狀態和層級結構。
  2. RUN指令的作用:在映像檔建置過程中執行特定的命令,如安裝軟體或修改組態,從而建立新的層級。
  3. CMDENTRYPOINT指令的作用:定義了容器啟動時的預設行為,CMD提供了預設引數,而ENTRYPOINT則指定了執行的命令或指令碼。
  4. ENVVOLUME指令的作用:分別用於設定環境變數和持久化儲存卷,增強了容器的可組態性和資料管理能力。

為何選擇Podman進行映像檔建置?

  1. 無根模式支援:Podman允許在無根模式下建置容器,提高了安全性和靈活性。
  2. 與Docker相容的語法:Podman與Docker具有相同的建置命令和語法,降低了遷移成本。

如何最佳化Dockerfile?

  1. 最小化層級數量:透過合併RUN指令減少層級數量,最佳化映像檔大小和建置效率。
  2. 利用快取機制:合理安排指令順序,使不常變化的指令靠前,以充分利用快取。

使用 Buildah 從零開始建立容器

基本映像檔建置與 Podman 的使用

在容器化的世界中,建立自定義映像檔是一項基本任務。Podman 提供了一個簡便的方式來建置容器映像檔,並且與 Docker 映像檔格式相容。以下是一個使用 Podman 建置自定義 httpd 伺服器映像檔的範例:

FROM fedora:33
# 安裝 httpd 套件並清理快取
RUN dnf install -y httpd && dnf clean all
# 設定 httpd 日誌輸出到 stdout 和 stderr
RUN sed -i 's|ErrorLog "logs/error_log"|ErrorLog /dev/stderr|' /etc/httpd/conf/httpd.conf && \
    sed -i 's|CustomLog "logs/access_log" combined|CustomLog /dev/stdout combined|' /etc/httpd/conf/httpd.conf && \
    chown 1001 /var/run/httpd
# 複製網頁內容
COPY index.html /var/www/html
# 定義內容卷冊
VOLUME /var/www/html
# 複製容器進入點指令碼
COPY entrypoint.sh /entrypoint.sh
# 宣告暴露的埠號
EXPOSE 8080
# 宣告預設使用者
USER 1001
ENTRYPOINT ["/entrypoint.sh"]
CMD ["httpd"]

內容解密:

  1. 基礎映像檔選擇:使用 fedora:33 作為基礎映像檔,確保容器具備基本的作業系統環境。
  2. httpd 套件安裝:使用 dnf 安裝 httpd 套件,並清理快取以節省映像檔空間。
  3. 日誌輸出設定:修改 httpd.conf 將日誌輸出重新導向到 stdoutstderr,便於容器日誌管理。
  4. 網頁內容複製:將 index.html 複製到 /var/www/html,作為伺服器的網頁根目錄。
  5. 卷冊定義:定義 /var/www/html 為卷冊,便於持久化儲存網頁內容。
  6. 進入點指令碼複製:複製 entrypoint.sh 到容器中,用於控制容器的啟動行為。
  7. 埠號暴露:宣告容器服務的埠號為 8080,以便外部存取。
  8. 預設使用者設定:設定預設使用者為 1001,以提升容器的安全性。

建置與標記映像檔

使用 Podman 建置映像檔:

$ podman build -t myhttpd .

建置完成後,可以檢視映像檔清單:

$ podman images | grep myhttpd
localhost/myhttpd latest 6dc90348520c 2 minutes ago 248 MB

對映像檔進行標記,以便推播到遠端倉函式庫:

$ podman tag localhost/myhttpd quay.io/<username>/myhttpd:v1.0

映像檔層級與壓縮

Podman 建置的映像檔由多個層級組成,可以使用 podman inspect 檢視層級資訊:

$ podman inspect myhttpd --format '{{ .RootFS.Layers }}'

若要減少層級數量,可以使用 --layers=false 選項重新建置映像檔:

$ podman build -t myhttpd --layers=false .

Meet Buildah:Podman 的建置工具

儘管 Podman 在建置 Dockerfiles/Containerfiles 時表現出色,但在更複雜的建置任務中,Dockerfiles/Containerfiles 的限制逐漸顯現。Buildah 的出現彌補了這一不足,提供更靈活的建置策略。

Buildah 是由與 Podman 相同的社群開發的開源專案,提供 OCI 相容的映像檔建置功能。Buildah 的主要優勢在於其靈活性和可程式設計性,允許使用者透過指令碼自定義建置流程。