使用 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 的更多信息,请查看以下资源

© . This site is unofficial and not affiliated with Kubernetes or Docker Inc.