首页
/ Moby 引擎构建与交叉编译实战:基于 Docker Buildx Bake 的 docker-bake.hcl 全解

Moby 引擎构建与交叉编译实战:基于 Docker Buildx Bake 的 docker-bake.hcl 全解

2026-09-04 21:21:47作者:尤辰城Agatha

本篇基于 ctn-build.md 贡献指南展开,讲解 Moby(Docker Engine 上游项目)如何利用根目录的 Dockerfiledocker-bake.hcl 构建定义,通过 docker buildx bake 完成 dockerd 及辅助工具的二进制构建与多平台交叉编译,并逐条拆解 bake 变量、target 与 Makefilehack/make.sh 底层脚本的协作关系,读完即可在本地复现官方 CI 同款构建链路。

构建体系总览

Moby 的构建体系围绕三个文件组织:

  • Dockerfile:根目录多阶段构建文件,声明了 Go 工具链、交叉编译助手 tonistiigi/xx、以及 containerd、runc、tini、rootlesskit、crun、containerutility 等依赖组件的独立构建阶段;
  • docker-bake.hcl:Buildx Bake 定义文件,声明了所有构建变量、target 与平台矩阵,是 docker buildx bake 命令的“配方”;
  • Makefile:把 docker buildx bake 封装成 make binarymake cross 等便捷入口,并负责把本地环境变量透传进构建容器。

正如 ctn-build.md 所述:Dockerfile 支持使用 Docker Buildx 与 BuildKit 构建和交叉编译 docker daemon 及额外工具,而 bake 定义正是为了简化这一过程而存在的。文档同时指出,set-up-dev-env.md 中“development container”一节介绍了如何在 Linux 容器中开发和编译改动,而二进制构建与交叉编译则由 bake 命令直接完成。

核心构建命令全解

以下是 ctn-build.md 给出的全部官方命令,按用途分组:

# build binaries for the current host platform
# output to ./bundles/binary-daemon by default
docker buildx bake
# or
docker buildx bake binary

# build binaries for the current host platform
# output to ./bin
DESTDIR=./bin docker buildx bake

# build dynamically linked binaries
# output to ./bundles/dynbinary-daemon by default
DOCKER_STATIC=0 docker buildx bake
# or
docker buildx bake dynbinary

# build binaries for all supported platforms
docker buildx bake binary-cross

# build binaries for a specific platform
docker buildx bake --set *.platform=linux/arm64

# build "complete" binaries (including containerd, runc, etc.)
docker buildx bake all

# build "complete" binaries for all supported platforms
docker buildx bake all-cross

# build non-runnable image wrapping "complete" binaries
# useful for use with undock and sharing via a registry
docker buildx bake bin-image

# build non-runnable image wrapping "complete" binaries, with custom tag
docker buildx bake bin-image --set "*.tags=foo/moby-bin:latest"

# build non-runnable image wrapping "complete" binaries for all supported platforms
# multi-platform images must be directly pushed to a registry
docker buildx bake bin-image-cross --set "*.tags=foo/moby-bin:latest" --push

逐条说明:

  1. docker buildx bake(不带 target)等价于 bake binary。原因在 docker-bake.hcl 中:group "default"targets = ["binary"],bake 默认执行 default group。
  2. 输出目录由 DESTDIR 变量控制docker-bake.hcl 定义了 DESTDIR 变量和一个 bindir 函数:DESTDIR != "" ? DESTDIR : "./bundles/${defaultdir}",所以默认落在 ./bundles/binary-daemon(静态)或 ./bundles/dynbinary-daemon(动态),设置 DESTDIR=./bin 后则落到 ./bin
  3. DOCKER_STATIC=0 生成动态链接二进制,与 bake dynbinary 等价。默认 DOCKER_STATIC=1,即静态构建;动态目标会输出到 bundles/dynbinary-daemon
  4. binary-cross 覆盖所有支持平台。平台清单定义在 docker-bake.hcl_platforms target 中:linux/amd64linux/arm/v5linux/arm/v6linux/arm/v7linux/arm64linux/ppc64lelinux/s390xwindows/amd64
  5. --set *.platform=linux/arm64 是 Buildx bake 的变量覆盖语法,可把任意 target 的平台收窄到单个平台做定向构建(例如只构建 Windows 版)。
  6. all / all-cross 构建“完整”二进制集,除 dockerd、docker-proxy 外还打包 containerd、runc 等配套工具,对应 Dockerfile 中的 all 阶段。
  7. bin-image / bin-image-cross 把“完整”二进制封装进一个不可运行(scratch 基底)的镜像,便于配合 undock 解包分发,或直接推送到 registry 共享。bin-image-cross 使用 type=image 输出,多平台镜像必须 --push 直接推送(因为多平台 manifest 本地无法落盘)。

深入 docker-bake.hcl:变量与 Target 矩阵

构建变量

docker-bake.hcl 顶部声明了以下变量,均可通过环境变量注入:

变量 默认值 作用
DOCKER_DEBUG "" 非空时开启调试:hack/make.sh 会加 -gcflags="all=-N -l" 禁用内联与优化,并打印构建命令
DOCKER_STATIC "1" 1 为静态链接,0 为动态链接(影响 dockerd 本体与 containerd、runc 等组件的构建方式)
DOCKER_LDFLAGS "" 追加给 go build -ldflags,可用于构建期注入值(见下文 Makefile 的 graphdriver 优先级示例)
DOCKER_BUILDTAGS "" 追加 Go build tag
DOCKER_GITCOMMIT null 指定写入二进制的 git 提交号
VERSION "" Docker 版本号,如 23.0.0-dev,通常由 Git ref 自动生成
PLATFORM "" 平台名,如 Docker Engine - Community
PRODUCT "" 产品名,用于 BuildKit 的 ExportedProduct,在不支持某特性的版本上给出友好报错
DEFAULT_PRODUCT_LICENSE "" 对应 version.DefaultProductLicense,可放置商业引擎的许可证摘要
PACKAGER_NAME "" 打包者名称,用于 Windows 清单的 CompanyName
DESTDIR "" 覆盖输出目录(见上)
SYSTEMD / FIREWALLD false 仅用于 dev target,决定开发容器是否安装 systemd、firewalld
GOVULNCHECK_FORMAT null govulncheck target 的输出格式

所有核心变量(除 DESTDIR 外的前 11 个)都被 _common target(docker-bake.hcl)以 args 形式统一注入 Dockerfile 构建,实现“一处声明、全局生效”。

Target 依赖关系

从源码结构看,各 target 通过 inherits 形成清晰的继承链:

  • binary:继承 _common,构建 Dockerfile 的 binary 阶段,输出 bindir(DOCKER_STATIC == "1" ? "binary" : "dynbinary")
  • dynbinary:继承 binary,强制 DOCKER_STATIC=0,输出固定为 dynbinary 目录;
  • binary-cross:继承 binary + _platforms,即“对全平台矩阵重复 binary 构建”;
  • binary-smoketest:继承 _common,构建 smoketest 阶段且 output = ["type=cacheonly"](不落盘产物,仅验证可编译可运行);
  • all:继承 _common,构建 all 阶段(完整工具集),输出目录规则同 binary
  • all-crossall + _platforms
  • bin-image:继承 alldocker-metadata-action(tags 为 moby-bin:local),输出 type=docker(本地镜像);
  • bin-image-cross:继承 bin-image,改 type=image 并枚举 7 个平台(含 windows/amd64);
  • dind:继承 _common,构建 dind 阶段,tag 为 docker-dind,输出本地镜像;
  • dev:继承 _common,构建 dev 阶段(即开发容器),额外透传 SYSTEMD/FIREWALLD,tag 为 docker-dev
  • govulncheck:使用独立的 hack/dockerfiles/govulncheck.Dockerfile,用于 Go 漏洞检查。

此外,default group 只包含 binary,这就是裸 docker buildx bake 的默认行为来源。

深入 Dockerfile:构建阶段如何工作

Dockerfile 是 bake 命令真正执行的构建脚本,关键设计点:

1. 交叉编译基础:tonistiigi/xx

Dockerfile 第一行即 FROM --platform=$BUILDPLATFORM tonistiigi/xx 阶段,把 xx 交叉编译工具集注入 base 阶段。之后各组件统一使用 xx-go buildxx-apt-get installxx-verify 等命令完成目标平台的 Go 编译、依赖安装和产物校验——这正是 binary-cross 能“一次 bake 出八平台产物”的底层机制。基础镜像由 GO_VERSION=1.26.8 与 Debian bookworm 的 golang 官方镜像构成(Dockerfile)。

2. 配套组件的独立阶段

每个辅助工具都是一个“src + build + OS 选择”三段式:

  • containerdDockerfile 从 containerd v2.3.4 源码构建 containerdcontainerd-shim-runc-v2ctrDOCKER_STATIC=1 时以 make STATIC=1CGO_ENABLED=0 编译并 xx-verify --static 校验静态链接。Windows 平台则回退到 binary-dummy 空阶段。
  • runcDockerfile 构建 runc v1.5.1,静态时执行 make static
  • tini(docker-init)Dockerfile 以 cmake 构建 tini-static,供容器 --init 使用。
  • rootlesskitDockerfile 静态时用 CGO_ENABLED=0 纯 Go 编译,动态时 -linkmode=external;同时把 contrib/dockerd-rootless.shcontrib/dockerd-rootless-setuptool.sh 拷入产物目录。
  • crun / containerutility(Windows)/ criu:分别见 DockerfileDockerfileDockerfile(criu 阶段当前因 opensuse 仓库稳定性被注释停用)。

3. buildbinaryall 阶段

  • buildDockerfile):安装 clang/lld 等依赖后,在 $BUILDPLATFORM 上执行 PKG_CONFIG=$(xx-go env PKG_CONFIG) ./hack/make.sh "$target",其中 DOCKER_STATIC=1target=binary(静态),否则 target=dynbinary;构建完成后用 xx-verify 校验 /tmp/bundles/<target>-daemon/dockerddocker-proxy,并把产物搬到 /build/ENV PREFIX=/tmp 是为了规避只读工作目录导致的 make.sh 输出失败。
  • binaryDockerfile):FROM scratch,仅拷贝 dockerd + docker-proxy;
  • allDockerfile):FROM scratch,额外 COPY --link 引入 tini、runc、containerd、rootlesskit、containerutility 各阶段的 /build/ 产物——这正是 bake all 所称“complete binaries”的由来。
  • smoketestDockerfile):在 base 上运行 file dockerd && dockerd --version && docker-proxy --version,用于 CI 上 binary-smoketest 的冒烟验证。
  • dindDockerfile):基于官方 docker:dind 镜像,把 cli、buildx、compose 插件与 all 阶段产物叠加进去,产出 docker-dind 开发用 DinD 镜像。

4. 从 make.sh 到 go build 的真实调用链

Dockerfile 的 build 阶段最终落到 hack/make.sh

  • hack/make.shbundle() 函数会 source hack/make/<bundle名>
  • hack/make/binary-daemonDOCKER_STATIC=1GO_PACKAGE='github.com/moby/moby/v2/cmd/dockerd'BINARY_NAME='dockerd' 调用 hack/make/.binary,并在目标平台与宿主机一致时把 runc、containerd、docker-init 等“嵌套可执行文件”一并拷入 bundle 目录;
  • hack/make/.binary 处理了动态构建的细节:非静态时在多数平台追加 -buildmode=pie(mips*/ppc64 除外);hack/make/.binary 中 Windows 下移除 netgo tag 以使用系统 DNS 解析器;hack/make/.binary 针对 arm/v5 交叉编译补充 -Wno-atomic-alignment-latomichack/make/.binary 最终执行带 -tags "netgo osusergo static_build nri_no_wasm ..."go build,并把 DOCKER_LDFLAGS 拼入 -ldflags

版本号方面,hack/make.sh 会解析 VERSION(支持 tag/分支/PR ref 归一化),hack/make.sh 则取 DOCKER_GITCOMMITgit rev-parse HEAD,工作区不干净时自动追加 -unsupported 后缀——这解释了 bake 变量为何要提供 VERSIONDOCKER_GITCOMMIT 两个注入点。

Makefile 封装与环境变量透传

不想手写 docker buildx bake 时,Makefile 提供了等价入口:

binary:      $(BAKE_CMD) binary            # 静态 linux 二进制
dynbinary:   $(BAKE_CMD) dynbinary          # 动态链接 linux 二进制
cross:       $(BAKE_CMD) binary-cross       # 全平台交叉构建
win:         $(BAKE_CMD) --set *.platform=windows/amd64 binary

(见 MakefileMakefile。)

Makefiledefault: binary,且 BAKE_CMD := $(BUILDX) bakeDOCKER_GITCOMMIT 在 Makefile 顶部即由 git rev-parse HEAD 计算并 export,因此 make binarydocker buildx bake binary 完全等价。MakefileDOCKER_ENVS 列表把 DOCKER_LDFLAGSVERSIONPLATFORMPRODUCT 等变量以 -e 形式透传进运行容器——其中注释给出了一个典型用法(Makefile):

make DOCKER_LDFLAGS="-X github.com/moby/moby/v2/daemon/graphdriver.priority=overlay2,zfs" dynbinary

即在构建期通过 -ldflags -X 改写内置的 graphdriver 优先级列表。

值得注意的约束:Makefile 明确说明不能把 DOCKER_BUILDTAGS 加入 -e 列表,因为即使 shell 中未设置,-e 也会遮蔽 Dockerfile 内的 ENV DOCKER_BUILDTAGS,而后者对官方构建很重要。

输出位置与产物结构速查

综合 bake 定义与 Dockerfile,各命令的产物去向如下:

命令 构建阶段 产物/输出位置
docker buildx bake / bake binary binary ./bundles/binary-daemon/DESTDIR 覆盖之)
docker buildx bake dynbinary binary(动态) ./bundles/dynbinary-daemon/
DESTDIR=./bin docker buildx bake binary ./bin/
docker buildx bake binary-cross / all-cross 全平台矩阵 各平台对应目录(本地 type=local 输出)
docker buildx bake all all ./bundles/{binary,dynbinary}-daemon/,含 containerd、runc 等
docker buildx bake bin-image all 本地镜像 moby-bin:local(scratch 基底,不可运行)
docker buildx bake bin-image-cross --push all 多平台 manifest 推送至 registry
make win binary(windows/amd64) dockerd.exe 等

小结

Moby 的二进制构建遵循“Dockerfile 定义能力,docker-bake.hcl 编排场景,Buildx bake 触发执行”的三层结构:DOCKER_STATICDESTDIRPLATFORMVERSION 等变量贯穿 bake 与 Dockerfile 两个文件,_common target 保证了变量注入的一致性;binary/all scratch 阶段与 tonistiigi/xx 工具链支撑了八平台的静态/动态交叉编译,而 hack/make.shhack/make/.binary 则把 Go 编译细节(build tags、PIE、ARM 标志、版本注入)封装在 bake 背后。贡献者按 docs/contributing/ctn-build.md 的命令操作,即可与 CI 使用完全相同的构建链路产出可复现的引擎二进制。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.78 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
987
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384