docker compose build 完整指南镜像构建、标签策略与底层实现解析【免费下载链接】composeDefine and run multi-container applications with Docker项目地址: https://gitcode.com/GitHub_Trending/compose/compose本指南基于 Docker Compose 官方命令参考文档 docs/reference/compose_build.md深入讲解docker compose build的命令语义、镜像命名与标签规则、全部可用的命令行选项并结合本仓库的 CLI 解析源码与构建后端实现说明该命令从解析 Compose 文件到产出镜像的完整底层链路。读完本文你将能准确掌握如何为单个或多个服务构建镜像、按需命中缓存、携带 SSH/构建参数、输出 Bake 文件以及配合 CI 进行推送与安全检查。命令概览与核心语义docker compose build用于构建或重新构建Compose 文件中声明了build段的服务镜像其命令形式为docker compose build [OPTIONS] [SERVICE...]其核心语义可以概括为三点均出自官方参考文档原文每个服务只构建一次然后被打上标签tag默认标签为project-service即项目名-服务名。如果 Compose 文件中为服务显式指定了image名称则构建产物会以该image名称打标签image字段中出现的环境变量在打标签之前会先进行变量插值。当你修改了某个服务的Dockerfile或它构建目录build context中的内容时需要重新执行docker compose build才能让镜像包含这些变更——普通docker compose up不会因为源码文件变更而自动触发重建。这一语义也在源码的 API 注释中被完整保留。docker compose build在 CLI 层映射到Compose接口的Build方法见 pkg/api/api.go 中 Build executes the equivalent to acompose build。默认镜像名的来源project-service 并不是一句笼统的说法而是由仓库中一个明确实现的函数决定的。在 pkg/api/api.go 中// Separator is used for naming components var Separator - // GetImageNameOrDefault computes the default image name for a service, used to tag built images func GetImageNameOrDefault(service types.ServiceConfig, projectName string) string { imageName : service.Image if imageName { imageName projectName Separator service.Name } return imageName }即服务没有显式配置image时镜像名 项目名 - 服务名。例如项目名为myapp、服务名为web构建出的镜像默认叫myapp-web。项目名默认取自 compose 文件所在目录名也可通过-p/--project-name、COMPOSE_PROJECT_NAME环境变量等方式显式指定相关标志定义见 cmd/compose/compose.go。若在兼容模式下运行--compatibilitySeparator会被替换为_以尽量贴近 Compose v1 的命名习惯见 cmd/compose/compose.go。完整的命令选项参考官方参考文档给出以下选项表其中部分选项为其他命令继承的全局选项名称类型默认值说明--build-argstringArray为服务设置构建期变量--builderstring指定要使用的 builder构建器--checkboolfalse检查构建配置--dry-runboolfalse以 dry run演练模式执行命令-m,--memorybytes0为构建容器设置内存上限。BuildKit 不支持--no-cacheboolfalse构建镜像时不使用缓存--printboolfalse打印等效的 bake 文件--provenancestring附加 provenance 来源证明attestation--pullboolfalse总是尝试拉取镜像的更新版本--pushboolfalse构建后推送服务镜像-q,--quietboolfalse抑制构建输出--sbomstring附加 SBOM 软件物料清单证明--sshstring构建服务镜像时使用的 SSH 认证传default使用默认 SSH Agent--with-dependenciesboolfalse连带构建可传递的依赖服务上表与命令行标志实现一一对应--dry-run定义在根命令的PersistentFlags上cmd/compose/compose.go因此对所有 compose 子命令生效其余选项在buildCommand中注册cmd/compose/build.go并集中保存在buildOptions结构体中。需要留意的隐藏DEPRECATED选项在 cmd/compose/build.go 中还注册了一批被标记隐藏的选项它们仅保留用于兼容旧版脚本功能已不再有意义--parallel已弃用默认true--compress已弃用使用 gzip 压缩构建上下文--force-rm已弃用总是删除中间容器--no-rm已弃用成功构建后不删除中间容器以及一个同为隐藏的--progress子选项。源码注释建议改用全局的docker compose --progress xx build若仍以子命令形式传参CLI 会向 stderr 打印迁移提示cmd/compose/build.go。因此参考文档的选项表只列出仍然有效的公开选项你在实际使用中不必关心这些隐藏标志。构建流程的两条后端路径从源码结构看docker compose build在执行时会根据环境自动选择两条不同的底层构建路径之一。命令入口runBuild最终调用backend.Build(ctx, project, apiBuildOptions)cmd/compose/build.go随后进入composeService.build做路径分流pkg/compose/build.gobake, err : buildWithBake(s.dockerCli) if err ! nil { return nil, err } if bake { return s.doBuildBake(ctx, project, serviceToBuild, options) } return s.doBuildClassic(ctx, project, serviceToBuild, options)buildWithBake的判定条件是pkg/compose/build_bake.goDocker 引擎启用了 BuildKit即没有把DOCKER_BUILDKIT显式设置为 0系统安装了buildxDocker CLI 插件。满足以上两点就走BuildKit buildx bake路径doBuildBake否则回退到经典构建器classic builderdoBuildClassic。当 buildx 缺失时CLI 会打印一条告警使用经典构建器将无法获得多架构构建、secrets、ssh、additional contexts 等 BuildKit 专属能力pkg/compose/build_bake.go。需要注意的是buildx 插件还有最低版本要求版本过低会直接报错compose build requires buildx x.y.z or later见 pkg/compose/build_bake.go。经典构建器路径doBuildClassic在经典路径下服务会按依赖顺序逐个调用 Docker 引擎的传统ImageBuild接口构建pkg/compose/build_classic.go。其特点包括本地目录上下文会被打包成 tar 并压缩后上传给 daemon过程中遵守.dockerignorepkg/compose/build_classic.go也支持 Git URL、远程 URL 上下文pkg/compose/build_classic.go不支持多平台multi-arch构建、privileged 模式、additional contexts、SSH keys、secrets 等特性一旦 compose 文件中出现这些配置会直接报错并提示改用 BuildKitpkg/compose/build_classic.go-m/--memory内存限制选项仅在经典路径生效这正是选项表中标注 Not supported by BuildKit 的原因构建选项会把它传入ImageBuildOptionspkg/compose/build_classic.go。BuildKit bake 路径doBuildBake在现代默认路径下compose 会先把项目里的构建配置翻译成一个bake 文件JSON再调用buildx bake执行pkg/compose/build_bake.go。翻译时每个服务的构建参数context、dockerfile、args、tags、cache-from/cache-to、platforms、secrets、ssh、entitlements等都会映射为 bake target见 pkg/compose/build_bake.go。bake target 名称由服务名转换而来其中的.会被替换为_若发生碰撞则追加_直至唯一pkg/compose/build_bake.go。bake 的输出类型根据场景自动选择pkg/compose/build_bake.go默认单平台且未要求推送时输出typedocker导入本地 Docker 引擎显式--push且服务配置了image时输出typeregistry直接推送仓库服务声明了多个platforms时输出typeimage,pushtrue|false。构建哪些服务目标选择、依赖与缓存跳过docker compose build可以不带任何服务名也可以携带一个或多个服务名作为参数例如只构建项目里的两个服务docker compose build web api服务选择与依赖关系在 pkg/compose/build.go 中可以看到服务选择逻辑不传服务名时默认选择项目内全部声明了build的服务options.Services project.ServiceNames()--with-dependencies对应结构体字段Deps会把服务选择策略从IgnoreDependencies切换为IncludeDependencies于是会连带构建所选服务的依赖服务且依赖关系是可传递的transitively服务内部的additional_contexts: service:xxx引用也会被解析为构建顺序上的依赖先构建作为上下文的那个服务对应源码是 pkg/compose/build_classic.go 中的WithServicesTransform处理以及build()里的addBuildDependencies。因此当你的镜像依赖另一个 compose 服务例如需要先把依赖服务构建出的镜像作为additional_context直接执行docker compose build svc也会自动保证底层服务先被构建。构建时不会盲目全量重建还有一层自动跳过逻辑需要特别说明在up --build、run --build等需要先确保镜像存在的复合场景中build()会先查本地是否已存在对应镜像——若镜像已存在于本地且服务的拉取策略不是build则该服务会被跳过而不重建pkg/compose/build.go。当你希望无条件强制重建时应显式执行docker compose build必要时加--no-cache或--pull。E2E 测试也验证了这一点例如 pkg/e2e/build_test.go 中再次up不再重建、up --build才触发重建。若最终没有发现任何需要构建的服务composeService.Build会打印一条No services to build警告pkg/compose/build.go这通常意味着你选中的服务都没有配置build段。构建选项在源码中的实际映射本小节把上表选项落到源码实现上帮助你理解每个开关最终变成了什么。--build-arg构建期变量--build-arg KEYVALUE可重复传入收集进opts.args经types.NewMappingWithEquals(opts.args)转为带覆盖语义的映射cmd/compose/build.go。之后会与 Docker 代理环境变量HTTP_PROXY等及 compose 文件中build.args合并解析最终既传入 bake target 的argspkg/compose/build_bake.go也传入经典构建的BuildArgspkg/compose/build_classic.go。注意 bake 路径会把参数中的${转义为$${以避免传给 buildx 时被二次插值。--no-cache与--pull两者均采用命令行或文件配置任一为真即启用的合并语义见 pkg/api/api.goservice.Build.Pull service.Build.Pull || o.Pull service.Build.NoCache service.Build.NoCache || o.NoCache--no-cache禁用 BuildKit 层缓存适合排查明明改了源码但镜像没变的问题--pull构建前总是尝试拉取基础镜像Dockerfile 中FROM引用的镜像的最新版本同时compose 文件里每个服务也可以分别声明build.pull/build.no_cache两者会合并生效。--ssh构建时使用 SSH Agent--ssh支持两种写法只写--ssh default使用当前默认的 SSH Agent或写--ssh idpath指定一个具体私钥路径。CLI 解析时会以第一个为界拆成 id 与路径若既没有且 id 也不是default则报invalid ssh keycmd/compose/build.go。解析结果既会传给 bake 的 ssh 列表也会追加到 compose 文件中服务声明的build.ssh之后pkg/compose/build_bake.go。另外有一个易踩的坑只传空的--ssh也等价于--ssh default——源码中若检测到该 flag 被显式使用但值为空会自动把值设为defaultcmd/compose/build.go。对应的 E2E 测试 pkg/e2e/build_test.go 验证了在未设置SSH_AUTH_SOCK时build --ssh会失败并提示invalid empty ssh agent socket而从 CLI 指定具体私钥--ssh fake-ssh./path/fake_rsa或从 compose 文件配置则能成功。--push构建并推送--push在 bake 路径下把输出从本地typedocker切换为typeregistry构建完成后镜像会被推送到image指定的仓库。如果服务没有配置image因而没有可推送的目标仓库--push会被静默忽略E2E 中专门有一个用例build --push ignored for unnamed images验证这一点pkg/e2e/build_test.go。在经典构建器路径中--push则表现为构建完每个服务后立即调用pushpkg/compose/build_classic.go。-q, --quiet抑制构建输出--quiet会把全局display.Mode切换为 quiet并把os.Stdout重定向到/dev/nullcmd/compose/build.go。E2E 用例build --quiet断言其 stdout 为空pkg/e2e/build_test.go适合在 CI 脚本中只关心构建结果而不关心日志。--print打印等效 bake 文件--print不会真正执行构建而是把翻译好的 bake 配置group/target结构以缩进 JSON 形式打印到 stdout 后直接返回pkg/compose/build_bake.go。这是调试构建参数、排查compose 到底给 buildx 传了什么的最直接手段。同样由于 bake 路径下runBuild会在 print 时挂上安静的事件处理器输出不会被多余日志污染cmd/compose/build.go。示例输出结构大致如下具体内容随 compose 文件不同而变{ group: { default: { targets: [web] } }, target: { web: { context: ., dockerfile: web/Dockerfile, tags: [myapp-web], platforms: [linux/amd64], outputs: [typedocker] } } }--check只校验不构建--check让 bake 以calllint模式运行pkg/compose/build_bake.go即让 BuildKit 的 linter 检查 Dockerfile/构建配置而不实际产出镜像。与--print类似它适合接入 CI 的静态检查阶段。注意该能力只在 bakeBuildKit路径下可用。--dry-run全局演练模式--dry-run是全局标志。bake 路径下的 dry run 会模拟构建事件为每个 target 生成dryRun-sha1形式的假镜像 ID并输出 writing image ...、 naming to tag等事件pkg/compose/build_bake.go便于在不实际构建的情况下预览会发生什么。dry run 通过compose.WithDryRun注入后端cmd/compose/compose.go。--provenance/--sbom供应链证明Compose 可以在构建产物上附加证明attestation--provenanceSLSA provenance来源证明记录镜像由谁、用什么方式构建--sbomSBOM软件物料清单列出镜像包含的软件组件。CLI 会将其追加为 buildx 的命令行参数--sbom...、--provenance...pkg/compose/build_bake.go。同时在runBuild中会无条件开启apiBuildOptions.Attestations truecmd/compose/build.go保证即使只使用 compose 文件里的build.attest/build.provenance/build.sbom配置也能正常生成证明。参数值支持true/false或更细粒度配置例如--provenancemodemax解析逻辑见 pkg/compose/build_bake.go。一个完整的实战示例以仓库 E2E 测试数据 pkg/e2e/testdata/TestBuildTags/compose.yaml 为参照一个带显式image和多个自定义 tag 的服务可以写成services: nginx: image: ${TAG_IMAGE} build: context: . tags: - docker.io/docker/${TAG_IMAGE}:1.0.0 - ${TAG_IMAGE}-other:v1.0.0在项目目录执行构建# 构建全部服务默认标签 project-service docker compose build # 只构建 nginx并连带其依赖 docker compose build --with-dependencies nginx # 禁用缓存强制重建同时注入构建期变量 docker compose build --no-cache --build-arg VERSION1.2.3 nginx # 构建并推送到 image 指定的仓库 docker compose build --push # 不真正构建只查看将要执行的 bake 配置 docker compose build --print # 校验构建配置仅 BuildKit/bake 路径支持 docker compose build --check # 演练模式观察将会产生的镜像名与标签事件 docker compose --dry-run build构建完成后可用docker compose images查看本项目的服务镜像或在构建时通过自定义 tag 的方式为镜像额外命名compose 会把image名与build.tags全部合并为镜像 tag见 pkg/compose/build_bake.go。常见问题速查改了代码再up为什么容器里还是旧镜像普通up不会因为源码变更重建镜像。需要显式docker compose build或使用docker compose up --build。为什么-m/--memory不生效该选项只作用于经典构建器在默认的 BuildKit 路径下会被忽略选项表已明确标注 Not supported by BuildKit。如需限制资源请改用 Docker/buildx 层面的资源限制。--push明明传了却不推送只有服务配置了显式image时才有可推送的仓库目标未配置image的服务会被自动忽略推送。构建很慢如何确认缓存命中情况先查看是否命中了自动跳过逻辑本地已有镜像且非build拉取策略必要时使用--no-cache强制全量构建排查并可用--print检查 bake 中的cache-from/cache-to配置是否正确传递。参考文档本体与对应源码入口命令参考docs/reference/compose_build.mdCLI 标志与解析cmd/compose/build.go构建 API 与默认命名pkg/api/api.go、pkg/api/api.go构建编排与路径选择pkg/compose/build.goBuildKit/bake 后端pkg/compose/build_bake.go经典构建后端pkg/compose/build_classic.goE2E 验证用例pkg/e2e/build_test.go【免费下载链接】composeDefine and run multi-container applications with Docker项目地址: https://gitcode.com/GitHub_Trending/compose/compose创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
