news 2026/10/10 1:35:30

Docker CLI 的 legacy builder:`docker image build` 命令完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Docker CLI 的 legacy builder:`docker image build` 命令完整指南
  • CLI
  • 开发工具

【免费下载链接】cli

The Docker CLI

项目地址:https://gitcode.com/gh_mirrors/cli5/cli
点击查看免费下载

导读

本文以 docs/reference/commandline/image_build.md 为骨架,系统讲解 Docker CLI 中docker image build(即 legacy builder)的完整行为:从全部命令行选项、构建上下文(build context)的传输与安全边界,到--isolation、--security-opt、--squash三个 legacy builder 专属特性的深入用法,并结合 cli/command/image/build.go 及上下文处理源码,剖析其底层实现与调用链。读完本文,你将理解 legacy builder 与 BuildKit 的行为差异,掌握在 Windows 容器场景下正确构建镜像的实战能力。

[!IMPORTANT] 本文描述的docker build属于legacy(pre-BuildKit)构建后端。Docker CLI 默认使用 Buildx(BuildKit),legacy builder 仅在构建 Windows 容器或显式设置DOCKER_BUILDKIT=0时生效。与 BuildKit 共有的通用特性(如--tag、--target),请参考docker buildx build的文档。

命令概览:别名的多重身份

docker image build是构建命令的"本体",但它同时拥有三个别名,全部指向同一实现:

  • docker image build
  • docker build
  • docker builder build

在 cli/command/image/build.go 中,命令的定义为build [OPTIONS] PATH | URL | -,并强制要求恰好一个位置参数(cli.ExactArgs(1)),这个位置参数就是构建上下文的来源。命令的 Annotations 中记录了完整的别名列表(cli/command/image/build.go#L107-L110),这与文档表格完全一致。

完整选项表:legacy builder 的全部参数

选项类型默认值说明
--add-hostlist添加自定义 host 到 IP 的映射(host:ip)
--build-arglist设置构建时变量
--cache-fromstringSlice作为缓存来源的镜像
--cgroup-parentstring为构建期间的RUN指令设置父 cgroup
--compressbool使用 gzip 压缩构建上下文
--cpu-periodint640限制 CPU CFS(完全公平调度器)周期
--cpu-quotaint640限制 CPU CFS(完全公平调度器)配额
-c,--cpu-sharesint640CPU 份额(相对权重)
--cpuset-cpusstring允许执行的 CPU 集合(如0-3、0,1)
--cpuset-memsstring允许执行的内存节点集合(如0-3、0,1)
-f,--filestringDockerfile 名称(默认是PATH/Dockerfile)
--force-rmbool始终移除中间容器
--iidfilestring将镜像 ID 写入指定文件
--isolationstring容器隔离技术(详见下文)
--labellist为镜像设置元数据
-m,--memorybytes0内存限制
--memory-swapbytes0交换限制(等于内存加交换,-1表示不限交换)
--networkstringdefault为构建期间的RUN指令设置网络模式
--no-cachebool构建时不要使用缓存
--platformstring当服务端支持多平台时设置平台
--pullbool总是尝试拉取镜像的更新版本
-q,--quietbool抑制构建输出,成功时仅打印镜像 ID
--rmbooltrue构建成功后移除中间容器
--security-optstringSlice安全选项(详见下文)
--shm-sizebytes0/dev/shm的大小
--squashbool将新构建的层压缩为单个新层(实验特性)
-t,--taglist以name:tag格式指定名称和标签
--targetstring设置要构建的目标构建阶段
--ulimitulimitUlimit 选项

以上选项与 cli/command/image/build.go 中注册的 flags 一一对应。其中几个值得注意的实现细节:

  • --rm的默认值是true:flags.BoolVar(&options.rm, "rm", true, ...)说明成功构建后默认清理中间容器;--force-rm则进一步强制清理(包括失败时的中间容器)。
  • --platform的默认值来自环境变量:flags.StringVar(&options.platform, "platform", os.Getenv("DOCKER_DEFAULT_PLATFORM"), ...)(build.go)。也就是说,你可以通过设置DOCKER_DEFAULT_PLATFORM环境变量来提供默认平台值。
  • --squash被标记为 experimental:flags.SetAnnotation("squash", "experimental", nil)(build.go)。
  • --disable-content-trust已废弃:源码中该 flag 被显式标记为 deprecated,说明 Docker 内容信任支持已被移除(build.go)。
  • --network选项要求 Docker API 版本不低于 1.25,--platform要求不低于 1.38,--squash要求不低于 1.25。

legacy builder 与 BuildKit:为什么还要用它?

定位与适用场景

legacy builder 从 Dockerfile 构建镜像的方式,是依次执行一系列提交(commit)操作——即每执行一个 Dockerfile 指令就生成一个新的镜像层,这一机制与docker commit类似(参见 container_commit.md)。相比之下,BuildKit 在构建效率和特性丰富度上全面领先,因此 legacy builder 已被弃用,唯一的例外场景是构建 Windows 容器——因为 BuildKit 尚未在 Windows 平台上达到完整的特性对等。

默认情况下docker build走的是 Buildx(BuildKit),除非满足以下任一条件:

  • 你在Windows 容器模式下运行 Docker Engine;
  • 你显式设置了环境变量DOCKER_BUILDKIT=0来退出 BuildKit。

从源码角度,cli/command/image/build.go 中的imageBuildOptions函数显式设置了Version: buildtypes.BuilderV1,这正是在 API 层面声明使用 legacy(Builder V1)构建器的关键证据——它把 CLI 侧收集到的所有选项映射为 Docker Engine 的ImageBuildOptions请求参数。

行为差异:只在 legacy builder 中不同的部分

本文只覆盖 legacy builder独有、或与 BuildKit行为不一致的内容。对于两者共通的选项(如--tag、--target、--build-arg等),其行为与docker buildx build一致,本文不展开赘述。

构建上下文:legacy builder 的传输模型

上下文是什么

构建上下文(build context)是调用构建命令时传入的位置参数。在下面的例子中,上下文是.,即当前工作目录:

$ docker build .

从源码看,构建上下文的类型由 context_detect.go 中的DetectContextType函数判定,支持四类来源:

  • stdin(-):从标准输入读取 tar 归档或 Dockerfile;
  • local:本地目录(默认方式);
  • git:Git URL,命令会先git clone到临时目录(context.go);
  • remote:远程 URL,作为 Dockerfile 或 tar 归档下载(context.go)。

关键差异:整包发送 vs 按需传输

legacy builder 将整个构建上下文完整发送给 daemon。它不会预先计算构建真正需要哪些文件——即使你只用到了上下文里的一小部分文件,大上下文也会导致传输耗时很长。而 BuildKit 只传输构建实际用到的文件。

因此,使用 legacy builder 时,精心设计上下文内容格外重要:

  • 只把构建必需的目录或文件指定为上下文;
  • 使用.dockerignore文件排除不需要发送的文件和目录。

.dockerignore的处理逻辑位于 dockerignore.go:ReadDockerignore读取上下文目录下的.dockerignore并解析出排除模式列表。随后在runBuild中,这些排除模式会与上下文目录一起交给archive.TarWithOptions(build.go)打包成 tar 流发送给 daemon——这正是"排除文件不进入上下文"的实现机制。

一个值得了解的细节:.dockerignore和指定的 Dockerfile 本身即使被排除规则命中,也会通过TrimBuildFilesFromExcludes(dockerignore.go)以!否定模式被"保回来",确保它们仍存在于上下文中供 daemon 使用。

访问构建上下文之外的路径

legacy builder 在 Dockerfile 中使用相对路径访问构建上下文之外的文件时会直接报错:

FROM alpine COPY ../../some-dir .
$ docker build . ... Step 2/2 : COPY ../../some-dir . COPY failed: forbidden path outside the build context: ../../some-dir ()

而 BuildKit 会剥离那些穿越构建上下文边界的相对路径前缀:上面的COPY ../../some-dir .在 BuildKit 下会被等价地解析为COPY some-dir .。

这一点在 CLI 源码中也有呼应:runBuild会检查 Dockerfile 的相对路径是否以../开头,若 Dockerfile 本身位于构建上下文之外,则单独读取该文件并注入上下文(build.go);Git 上下文场景下若 Dockerfile 必须位于上下文内,否则报错(context.go)。测试用例 build_test.go(TestRunBuildDockerfileOutsideContext)验证了"上下文外的 Dockerfile 也能被正确注入构建请求"的行为。

实战示例:legacy builder 专属特性

--isolation:指定容器隔离技术

该选项在 Windows 上运行 Docker 容器时非常有用。--isolation=<value>用于设置容器的隔离技术:

  • 在Linux上,唯一支持的值是default(使用 Linux namespaces);
  • 在Microsoft Windows上,可以指定以下值:
值说明
default使用 Docker daemon 的--exec-opt指定的值。若 daemon 未指定隔离技术,Microsoft Windows 默认使用process
process仅使用命名空间隔离
hyperv基于 Hyper-V 虚拟机分区隔离

在源码中,--isolation选项通过container.Isolation(options.isolation)转换后写入构建请求(build.go),是 Windows 容器构建路径上直接影响容器运行时隔离级别的参数。

--security-opt:可选安全选项

该 flag仅在 Windows 上运行的 daemon 中受支持,且只支持credentialspec选项。credentialspec的取值格式必须是file://spec.txt或registry://keyname,用于为 Windows 容器指定凭据规范。

在源码中它作为stringSlice收集并直接透传给构建请求的SecurityOpt字段(build.go),不对值做额外校验——格式合法性由 daemon 侧负责。

--squash:合并镜像层(实验特性)

[!NOTE]--squash属于实验特性,不应被视为稳定功能。

原理概述

镜像构建完成后,该 flag 会把新产生的层合并成一个单一新层,生成一个新镜像。关键点:

  • Squashing不会破坏任何已有镜像,而是创建一个内容等价、但层被合并的新镜像;
  • 效果上相当于所有Dockerfile指令看起来是在一个层中完成的;
  • --squash保留构建缓存(缓存中的各层原样保留,squash 只是额外生成一份合并后的镜像)。
什么时候该用(或不该用)

有益的场景:Dockerfile 产生了多层且多次修改同一批文件,例如一个步骤创建文件、另一个步骤又删除它——squash 可以消除这些"层间冗余"。

可能有害的场景:

  • 多层的镜像被拉取时,daemon 可以并行拉取各层,并且允许镜像之间共享层以节省空间;squash 会破坏这种层共享能力;
  • 单一层在下载时无法并行化,提取也更慢,可能对性能产生负面影响。

更好的替代方案:对于大多数场景,多阶段构建(multi-stage builds)是更优选择——它提供更细粒度的构建控制,并能利用 builder 未来的优化能力。

已知限制
  • 合并层后,生成的镜像无法与其他镜像共享层(基础镜像的共享仍然支持),可能显著占用更多空间;
  • 由于同时保存"含完整缓存层的构建缓存镜像"和"合并后的版本"两份拷贝,磁盘占用可能明显增加;
  • 合并可能产生更小的镜像,但单层提取时间更长、无法并行下载单层,性能上可能有负面影响;
  • 若被 squash 的镜像没有对文件系统做任何修改(例如 Dockerfile 只包含ENV指令),squash 步骤会失败。
前置条件:启用实验模式

本页示例基于 Docker 23.03 的 experimental 模式(原文档示例输出展示的是 Docker 28.5.1 的版本信息,二者仅作运行环境参考)。启用方式有两种:

  • 启动 Docker daemon 时使用--experimentalflag;
  • 在daemon.json配置文件中设置"experimental": true。

默认情况下实验模式是禁用的。可以使用docker version查看当前配置,检查Engine部分的Experimental行:

Client: Docker Engine - Community Version: 28.5.1 API version: 1.51 Go version: go1.24.8 Git commit: e180ab8 Built: Wed Oct 8 12:16:17 2025 OS/Arch: darwin/arm64 Context: desktop-linux Server: Docker Engine - Community Engine: Version: 28.5.1 API version: 1.51 (minimum version 1.24) Go version: go1.24.8 Git commit: f8215cc Built: Wed Oct 8 12:18:25 2025 OS/Arch: linux/arm64 Experimental: true [...]

Experimental: true即表示实验模式已开启。

实操:用--squash构建镜像

以下是一个使用--squash构建的完整示例。先准备如下Dockerfile:

FROM busybox RUN echo hello > /hello RUN echo world >> /hello RUN touch remove_me /remove_me ENV HELLO=world RUN rm /remove_me

注意此 Dockerfile 的设计意图:/hello被两次写入、remove_me被创建后又删除——正是前面提到的"多层修改同一批文件"的典型场景。

使用--squash构建名为test的镜像:

$ docker build --squash -t test .

构建完成后,查看镜像历史(history)。可以看到:各层名称显示为<missing>,且出现了一个COMMENT为merge的新层——这就是被合并出来的层:

$ docker history test IMAGE CREATED CREATED BY SIZE COMMENT 4e10cb5b4cac 3 seconds ago 12 B merge sha256:88a7b0112a41826885df0e7072698006ee8f621c6ab99fca7fe9151d7b599702 to sha256:47bcc53f74dc94b1920f0b34f6036096526296767650f223433fe65c35f149eb <missing> 5 minutes ago /bin/sh -c rm /remove_me 0 B <missing> 5 minutes ago /bin/sh -c #(nop) ENV HELLO=world 0 B <missing> 5 minutes ago /bin/sh -c touch remove_me /remove_me 0 B <missing> 5 minutes ago /bin/sh -c echo world >> /hello 0 B <missing> 6 minutes ago /bin/sh -c echo hello > /hello 0 B <missing> 7 weeks ago /bin/sh -c #(nop) CMD ["sh"] 0 B <missing> 7 weeks ago /bin/sh -c #(nop) ADD file:47ca6e777c36a4cfff 1.113 MB

注意顶部的merge层SIZE仅为 12 B——它只包含合并后的差异内容(删除了/remove_me、保留了/hello与HELLO=world),而原始中间层(如touch remove_me /remove_me创建的 0 B 占位层与rm操作)都保留在构建缓存的历史记录中。

验证镜像结果,确认:

  • /remove_me已被删除;
  • /hello的内容是hello\nworld;
  • 环境变量HELLO的值为world。

从源码看构建全流程

结合 cli/command/image/build.go 的runBuild函数,可以把 legacy builder 的完整调用链梳理如下:

  1. 校验平台:若指定了--platform,先通过platforms.Parse校验其合法性;
  2. 检测上下文类型:DetectContextType判定 stdin / 本地 / Git / 远程四类来源;
  3. 禁止双重 stdin:若同时用 stdin 作为 Dockerfile 和构建上下文,直接报错can't use stdin for both build context and dockerfile;
  4. 准备上下文:本地目录会先读取.dockerignore、校验目录可读性,再打包成 tar 流;Git 上下文先克隆到临时目录;远程 URL 则下载为 Dockerfile 或 tar;
  5. 压缩与进度上报:--compress时用 gzip 压缩上下文;--quiet时所有输出被缓冲,最终只打印镜像 ID;
  6. 构造请求:imageBuildOptions汇总所有选项,其中Version: BuilderV1显式指定 legacy 构建后端,同时附带来自config.json的认证信息;
  7. 发送与解析:调用ImageBuildAPI,通过jsonstream.Display处理 daemon 返回的 JSON 流,并从aux消息中解析出最终的镜像 ID;
  8. 收尾:--quiet时输出镜像 ID;--iidfile时将镜像 ID 写入指定文件(若服务端未返回镜像 ID 则报错)。

这套流程解释了文档中的多个行为:为什么-q只输出镜像 ID、为什么--iidfile能在脚本流水线中拿到构建结果、为什么 legacy builder 必须先完整打包上下文再传输——一切都源于这个"客户端整包打包 + API 透传"的架构。

小结

docker image build作为 legacy builder 的命令入口,在 Docker CLI 中仍承担着 Windows 容器构建的职责。使用它的关键在于牢记三点:默认会被 BuildKit 取代(除非 Windows 容器模式或DOCKER_BUILDKIT=0)、构建上下文会整包发送(必须善用.dockerignore)、--isolation/--security-opt/--squash是其专属特性。理解这些差异与底层源码实现,能帮助你在正确的场景中做出正确的构建选择。

  • CLI
  • 开发工具

【免费下载链接】cli

The Docker CLI

项目地址:https://gitcode.com/gh_mirrors/cli5/cli
点击查看免费下载
上一篇:扫码3步导出QQ空间全部说说与图片:GetQzonehistory 实战教程
下一篇:B站视频下载神器BilibiliDown:5分钟搞定批量下载与音频提取

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/10 1:34:35

基于 Go + Vue 的个人数字生活管理系统

Spring-_-Bear 的 CSDN 博客导航 文章目录SelfHub&#xff08;一隅&#xff09;✨ 核心特性&#x1f6e0;️ 技术栈&#x1f680; 快速开始后端服务部署前端应用部署默认登录账户&#x1f4f1; 功能模块&#x1f510; 登录页&#x1f4ca; 知行录统计看板任务列表完成情况&…

作者头像 李华
网站建设 2026/10/10 1:33:50

工程师必备:这5款Modbus调试工具,狠狠收藏吧!

盘点5款Modbus通讯检测工具&#xff0c;几乎是PLC工程师、嵌入式工程师、MES工程师必备的工具。 干货还是蛮多的&#xff0c;如有帮助&#xff0c;点赞记录一下吧。 ModbusPoll、ModbusSlave&#xff1a;最经典的Modbus协议调试工具&#xff0c;有多个版本包括便携版本、汉化版…

作者头像 李华
网站建设 2026/10/10 1:30:43

高保湿洗面奶OEM代工怎么做不踩坑?车间老炮拆解料体公差与防比价模型

拿着某美系K家高保湿洁面的空瓶来找源头厂做品质定制&#xff0c;做出来料体稀得像兑了水——客户搓两把就抱怨假滑、洗不干净。这种单子我每月在车间至少劝退三波。不是做不出来&#xff0c;而是不少白牌定制方压根不懂洁面乳的配方架构&#xff0c;只盯着瓶子上的字面意思压成…

作者头像 李华
网站建设 2026/10/10 1:28:38

学英语的捷径是背单词,背单词的捷径是母词

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/10 1:28:27

咨询沉淀硬化钢加工材料、了解沉淀硬化钢加工多少钱、推荐几家靠谱的沉淀硬化钢加工源头厂家

咨询沉淀硬化钢加工材料、了解沉淀硬化钢加工价格、寻找靠谱的源头厂家&#xff0c;是许多装备制造、航空航天、泵阀与精密机械企业采购工作中的高频事项。沉淀硬化钢174PH、177PH、SUS630、SUS631、155PH、138PH等牌号&#xff0c;兼具高强度与耐蚀性&#xff0c;广泛用于轴类…

作者头像 李华