使用 Bake 构建 Compose 项目
本指南探讨了如何使用 Bake 为包含多个服务的 Docker Compose 项目构建镜像。
Docker Buildx Bake 是一个构建编排工具,它支持对构建进行声明式配置,就像 Docker Compose 用于定义运行时堆栈一样。对于使用 Docker Compose 启动本地开发服务的项目,Bake 提供了一种将生产就绪型构建配置无缝扩展到项目中的方法。
先决条件
本指南假定您熟悉
概览
本指南将使用 dvdksn/example-voting-app 仓库作为使用 Docker Compose 的单体仓库示例,该仓库可以使用 Bake 进行扩展。
$ git clone https://github.com/dvdksn/example-voting-app.git
$ cd example-voting-app
该仓库使用 Docker Compose 在 compose.yaml
文件中定义应用程序的运行时配置。此应用程序包含以下服务:
服务 | 描述 |
---|---|
vote | 一个用 Python 编写的前端 Web 应用,允许您在两个选项之间投票。 |
result | 一个 Node.js Web 应用,实时显示投票结果。 |
worker | 一个 .NET worker,它消费投票并将其存储在数据库中。 |
db | 一个由 Docker 卷支持的 Postgres 数据库。 |
redis | 一个收集新投票的 Redis 实例。 |
seed | 一个用于向数据库填充模拟数据的实用容器。 |
vote
、result
和 worker
服务是从本仓库中的代码构建的,而 db
和 redis
使用 Docker Hub 中预先存在的 Postgres 和 Redis 镜像。seed
服务是一个实用程序,用于对前端服务发起请求以填充数据库,用于测试目的。
使用 Compose 构建
当您启动一个 Docker Compose 项目时,任何定义了 build
属性的服务都会在服务启动之前自动构建。以下是示例仓库中 vote
服务的构建配置:
services:
vote:
build:
context: ./vote # Build context
target: dev # Dockerfile stage
vote
、result
和 worker
服务都指定了构建配置。运行 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 Configuration Language (HCL)、JSON 和 Docker Compose YAML 格式。当您将 Bake 与多个文件一起使用时,它会找到并合并所有适用的配置文件,形成一个统一的构建配置。在 Bake 文件中指定的选项会扩展或在某些情况下覆盖您 Compose 文件中定义的构建选项。
以下部分探讨了如何使用 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 文件并添加以下配置:
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/amd64
和 linux/arm64
架构生成三组多平台镜像。每个镜像都带有作者注解以及 SBOM 和来源证明记录。
结论
本指南演示的模式提供了一种有用的方法,用于在使用 Docker Compose 的项目中管理生产就绪型 Docker 镜像。使用 Bake 可以让您访问 Buildx 和 BuildKit 的所有强大功能,并且还有助于以合理的方式分离您的开发和构建配置。
进一步阅读
有关如何使用 Bake 的更多信息,请查阅以下资源: