使用 Bake 構建 Compose 專案

本指南探討了如何使用 Bake 為具有多個服務的 Docker Compose 專案構建映象。

Docker Buildx Bake 是一款構建編排工具,它能為您的構建提供宣告式配置,就像 Docker Compose 為定義執行時堆疊所做的一樣。對於使用 Docker Compose 啟動服務進行本地開發的專案,Bake 提供了一種無縫擴充套件專案的方法,使其具備生產就緒的構建配置。

先決條件

本指南假設您熟悉

概覽

本指南將使用 dvdksn/example-voting-app 倉庫作為示例,這是一個使用 Docker Compose 的 monorepo,可以透過 Bake 進行擴充套件。

$ git clone https://github.com/dvdksn/example-voting-app.git
$ cd example-voting-app

此倉庫在 compose.yaml 檔案中使用 Docker Compose 來定義執行應用程式的執行時配置。該應用包含以下服務

服務描述
vote一個 Python 前端 Web 應用,讓您可以在兩個選項之間投票。
result一個 Node.js Web 應用,即時顯示投票結果。
worker一個 .NET worker,用於處理投票並將其儲存到資料庫中。
db一個由 Docker volume 支援的 Postgres 資料庫。
redis一個 Redis 例項,用於收集新的投票。
seed一個實用工具容器,用於向資料庫填充模擬資料。

voteresultworker 服務是基於此倉庫中的程式碼構建的,而 dbredis 則使用來自 Docker Hub 的現有 Postgres 和 Redis 映象。seed 服務是一個實用工具,它呼叫對前端服務的請求來填充資料庫,以供測試之用。

使用 Compose 構建

當您啟動一個 Docker Compose 專案時,任何定義了 build 屬性的服務都會在服務啟動前自動構建。以下是示例倉庫中 vote 服務的構建配置

compose.yaml
services:
  vote:
    build:
      context: ./vote # Build context
      target: dev # Dockerfile stage

voteresultworker 服務都指定了構建配置。執行 docker compose up 將觸發這些服務的構建。

您知道嗎?您也可以只使用 Compose 來構建服務映象。docker compose build 命令允許您使用 Compose 檔案中指定的構建配置來呼叫構建。例如,要使用此配置構建 vote 服務,請執行

$ docker compose build vote

省略服務名稱可以一次性構建所有服務

$ docker compose build

當您只需要構建映象而無需執行服務時,docker compose build 命令非常有用。

Compose 檔案格式支援許多用於定義構建配置的屬性。例如,要為映象指定標籤名稱,請在服務上設定 image 屬性。

services:
  vote:
    image: username/vote
    build:
      context: ./vote
      target: dev
    #...

  result:
    image: username/result
    build:
      context: ./result
    #...

  worker:
    image: username/worker
    build:
      context: ./worker
    #...

執行 docker compose build 會建立三個服務映象,它們帶有完全限定的映象名稱,您可以將這些映象推送到 Docker Hub。

build 屬性支援多種用於配置構建的選項。然而,構建生產級映象通常與本地開發使用的映象不同。為了避免在 Compose 檔案中堆積可能不適用於本地構建的配置,可以考慮使用 Bake 來構建釋出映象,從而將生產構建與本地構建分開。這種方法分離了關注點:使用 Compose 進行本地開發,使用 Bake 進行生產就緒的構建,同時仍然複用服務定義和基本的構建配置。

使用 Bake 構建

與 Compose 類似,Bake 從配置檔案中解析專案的構建定義。Bake 支援 HashiCorp 配置語言(HCL)、JSON 和 Docker Compose YAML 格式。當您將 Bake 與多個檔案一起使用時,它會查詢併合並所有適用的配置檔案,形成一個統一的構建配置。在 Compose 檔案中定義的構建選項會被 Bake 檔案中指定的選項擴充套件,或在某些情況下被覆蓋。

下一節將探討如何使用 Bake 來擴充套件 Compose 檔案中為生產環境定義的構建選項。

檢視構建配置

Bake 會根據您服務的 build 屬性自動建立一個構建配置。使用 Bake 的 --print 標誌可以檢視給定 Compose 檔案的構建配置。此標誌會評估構建配置並以 JSON 格式輸出構建定義。

$ docker buildx bake --print

JSON 格式的輸出顯示了將要執行的組,以及該組的所有目標。一個組是構建的集合,一個目標代表一個單一的構建。

{
  "group": {
    "default": {
      "targets": [
        "vote",
        "result",
        "worker",
        "seed"
      ]
    }
  },
  "target": {
    "result": {
      "context": "result",
      "dockerfile": "Dockerfile",
    },
    "seed": {
      "context": "seed-data",
      "dockerfile": "Dockerfile",
    },
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "target": "dev",
    },
    "worker": {
      "context": "worker",
      "dockerfile": "Dockerfile",
    }
  }
}

如您所見,Bake 建立了一個 default 組,其中包含四個目標

  • seed
  • vote
  • result
  • worker

這個組是根據您的 Compose 檔案自動建立的;它包含了所有包含構建配置的服務。要使用 Bake 構建這組服務,請執行

$ docker buildx bake

自定義構建組

首先重新定義 Bake 執行的預設構建組。當前的預設組包括一個 seed 目標——一個僅用於向資料庫填充模擬資料的 Compose 服務。由於此目標不產生生產映象,因此無需將其包含在構建組中。

要自定義 Bake 使用的構建配置,請在倉庫根目錄下,與 compose.yaml 檔案同級,建立一個名為 docker-bake.hcl 的新檔案。

$ touch docker-bake.hcl

開啟 Bake 檔案並新增以下配置

docker-bake.hcl
group "default" {
  targets = ["vote", "result", "worker"]
}

儲存檔案並再次列印您的 Bake 定義。

$ docker buildx bake --print

JSON 輸出顯示,default 組現在只包含您關心的目標。

{
  "group": {
    "default": {
      "targets": ["vote", "result", "worker"]
    }
  },
  "target": {
    "result": {
      "context": "result",
      "dockerfile": "Dockerfile",
      "tags": ["username/result"]
    },
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "tags": ["username/vote"],
      "target": "dev"
    },
    "worker": {
      "context": "worker",
      "dockerfile": "Dockerfile",
      "tags": ["username/worker"]
    }
  }
}

在這裡,每個目標的構建配置(上下文、標籤等)都從 compose.yaml 檔案中獲取。而組則由 docker-bake.hcl 檔案定義。

自定義目標

Compose 檔案目前將 dev 階段定義為 vote 服務的構建目標。這對於您在本地開發中執行的映象來說是合適的,因為 dev 階段包含了額外的開發依賴和配置。然而,對於生產映象,您會希望轉而使用 final 映象作為目標。

要修改 vote 服務使用的目標階段,請將以下配置新增到 Bake 檔案中

target "vote" {
  target = "final"
}

當您使用 Bake 執行構建時,這會覆蓋 Compose 檔案中指定的 target 屬性,使用一個不同的值。Compose 檔案中的其他構建選項(標籤、上下文)保持不變。您可以透過使用 docker buildx bake --print vote 檢查 vote 目標的構建配置來驗證這一點

{
  "group": {
    "default": {
      "targets": ["vote"]
    }
  },
  "target": {
    "vote": {
      "context": "vote",
      "dockerfile": "Dockerfile",
      "tags": ["username/vote"],
      "target": "final"
    }
  }
}

其他構建特性

生產級構建通常與開發構建具有不同的特點。以下是您可能希望為生產映象新增的一些示例。

多平臺
對於本地開發,您只需要為本地平臺構建映象,因為這些映象只會在您的機器上執行。但對於推送到登錄檔的映象,通常最好為多個平臺構建,特別是 arm64 和 amd64。
證明
證明(Attestations)是附加到映象的清單,描述了映象是如何建立的以及它包含哪些元件。將證明附加到您的映象有助於確保您的映象遵循軟體供應鏈的最佳實踐。
註解
註解(Annotations)為映象提供描述性元資料。使用註解來記錄任意資訊並將其附加到您的映象上,這有助於消費者和工具瞭解映象的來源、內容以及如何使用它。
提示

為什麼不直接在 Compose 檔案中定義這些額外的構建選項呢?

Compose 檔案格式中的 build 屬性並不支援所有構建功能。此外,一些功能,如多平臺構建,會顯著增加構建服務所需的時間。對於本地開發,最好保持構建步驟簡單快速,將那些花哨的功能留給釋出構建。

要將這些屬性新增到您使用 Bake 構建的映象中,請按如下方式更新 Bake 檔案

group "default" {
  targets = ["vote", "result", "worker"]
}

target "_common" {
  annotations = ["org.opencontainers.image.authors=username"]
  platforms = ["linux/amd64", "linux/arm64"]
  attest = [
    "type=provenance,mode=max",
    "type=sbom"
  ]
}

target "vote" {
  inherits = ["_common"]
  target = "final"
}

target "result" {
  inherits = ["_common"]
}

target "worker" {
  inherits = ["_common"]
}

這定義了一個新的 _common 目標,該目標定義了可重用的構建配置,用於為您的映象新增多平臺支援、註解和證明。這個可重用的目標由其他構建目標繼承。

透過這些更改,使用 Bake 構建專案會為 linux/amd64linux/arm64 架構生成三組多平臺映象。每個映象都帶有一個作者註解,以及 SBOM 和來源證明記錄。

結論

本指南中演示的模式為在使用 Docker Compose 的專案中管理生產就緒的 Docker 映象提供了一種有用的方法。使用 Bake 讓您可以訪問 Buildx 和 BuildKit 的所有強大功能,並且有助於以一種合理的方式分離您的開發和構建配置。

進一步閱讀

有關如何使用 Bake 的更多資訊,請檢視以下資源