docker build(旧版构建器)

描述从 Dockerfile 构建镜像
用法docker image build [OPTIONS] PATH | URL | -
别名
docker image build docker build docker builder build

描述

重要提示

本页面指的是 docker build旧版实现,它使用旧版(非 BuildKit)构建后端。此配置仅在构建 Windows 容器时相关。

有关使用 Buildx 的默认 docker build 的信息,请参阅 docker buildx build

使用旧版构建器构建时,镜像是通过运行一系列提交从 Dockerfile 创建的。与使用 BuildKit 相比,此过程效率低下且速度缓慢,这就是除构建 Windows 容器外,此构建策略已弃用的原因。它对于构建 Windows 容器仍然有用,因为 BuildKit 尚未完全支持 Windows 功能。

除非满足以下条件,否则使用 docker build 调用的构建默认使用 Buildx(和 BuildKit):

  • 您正在 Windows 容器模式下运行 Docker Engine
  • 您通过设置环境变量 DOCKER_BUILDKIT=0 明确选择不使用 BuildKit。

本页上的描述仅涵盖旧版构建器特有的信息,以及旧版构建器行为与 BuildKit 行为不同的情况。有关旧版构建器和 BuildKit 共有的功能和标志(例如 --tag--target)的信息,请参阅 docker buildx build 的文档。

旧版构建器的构建上下文

构建上下文是您调用构建命令时传递的位置参数。在以下示例中,上下文是 .,表示当前工作目录。

$ docker build .

使用旧版构建器时,构建上下文会完整地发送到守护进程。使用 BuildKit,仅传输构建中使用的文件。旧版构建器不会提前计算需要哪些文件。这意味着对于具有大型上下文的构建,即使您仅使用上下文中包含的文件子集,上下文传输也可能需要很长时间。

因此,使用旧版构建器时,仔细考虑您在指定的上下文中包含哪些文件尤为重要。使用 .dockerignore 文件排除构建中不需要发送到构建上下文中的文件和目录。

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

如果您尝试在 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 .

选项

选项默认值描述
--add-host添加自定义的主机到 IP 映射(host:ip
--build-arg设置构建时变量
--cache-from要用作缓存源的镜像
--cgroup-parent在构建期间为 RUN 指令设置父 cgroup
--compress使用 gzip 压缩构建上下文
--cpu-period限制 CPU CFS(完全公平调度器)周期
--cpu-quota限制 CPU CFS(完全公平调度器)配额
-c, --cpu-sharesCPU 份额(相对权重)
--cpuset-cpus允许执行的 CPU(0-3,0,1)
--cpuset-mems允许执行的内存节点(0-3,0,1)
--disable-content-trusttrue跳过镜像验证
-f, --fileDockerfile 的名称(默认是 PATH/Dockerfile
--force-rm总是删除中间容器
--iidfile将镜像 ID 写入文件
--isolation容器隔离技术
--label为镜像设置元数据
-m, --memory内存限制
--memory-swapSwap 限制等于内存加上 Swap:-1 表示无限制 Swap
--networkAPI 1.25+ 在构建期间为 RUN 指令设置网络模式
--no-cache构建镜像时不要使用缓存
--platformAPI 1.38+ 如果服务器支持多平台,则设置平台
--pull总是尝试拉取更新版本的镜像
-q, --quiet抑制构建输出并在成功时打印镜像 ID
--rmtrue构建成功后删除中间容器
--security-opt安全选项
--shm-size/dev/shm 的大小
--squashAPI 1.25+ 实验性(守护进程) 将新构建的层压缩成一个新层
-t, --tag名称以及可选的 name:tag 格式的标签
--target设置要构建的目标构建阶段。
--ulimitUlimit 选项

示例

为容器指定隔离技术(--isolation)

此选项在 Windows 上运行 Docker 容器的情况下非常有用。--isolation=<value> 选项设置容器的隔离技术。在 Linux 上,唯一受支持的选项是使用 Linux 命名空间的 default 选项。在 Microsoft Windows 上,您可以指定以下值

描述
default使用 Docker 守护进程的 --exec-opt 指定的值。如果 daemon 未指定隔离技术,Microsoft Windows 将使用 process 作为其默认值。
process仅命名空间隔离。
hyperv基于 Hyper-V 虚拟机监控程序分区的隔离。

可选安全选项(--security-opt)

此标志仅在 Windows 上运行的守护进程上受支持,并且仅支持 credentialspec 选项。credentialspec 的格式必须是 file://spec.txtregistry://keyname

压缩镜像层(--squash)(实验性)

概述

注意

--squash 选项是一项实验性功能,不应视为稳定功能。

镜像构建完成后,此标志会将新层压缩到包含单个新层的新镜像中。压缩不会破坏任何现有镜像,而是创建一个包含压缩层内容的新镜像。这有效地使所有 Dockerfile 命令看起来是使用单个层创建的。--squash 标志会保留构建缓存。

如果您的 Dockerfile 生成了修改相同文件的多个层,压缩层可能会有益。例如,在一个步骤中创建并在另一个步骤中删除的文件。对于其他用例,压缩镜像实际上可能对性能产生负面影响。当拉取由多个层组成的镜像时,守护进程可以并行拉取层,并允许在镜像之间共享层(节省空间)。

对于大多数用例,多阶段构建是更好的替代方案,因为它们提供对构建的更精细控制,并且可以利用构建器未来的优化。有关更多信息,请参阅多阶段构建部分。

已知限制

--squash 选项有一些已知限制

  • 压缩层时,生成的镜像无法利用与其他镜像的层共享,并且可能会占用更多空间。基础镜像的共享仍然支持。
  • 使用此选项时,由于存储了镜像的两个副本,您可能会看到更多空间被占用:一个用于包含所有完整缓存层的构建缓存,另一个用于压缩版本。
  • 虽然压缩层可能会生成更小的镜像,但它可能会对性能产生负面影响,因为单个层提取需要更长时间,而且无法并行下载单个层。
  • 尝试压缩未对文件系统进行更改的镜像时(例如,Dockerfile 只包含 ENV 指令),压缩步骤将失败(请参阅问题 #33823)。

先决条件

本页上的示例使用 Docker 23.03 中的实验模式。

您可以通过在启动 Docker 守护进程时使用 --experimental 标志或在 daemon.json 配置文件中设置 experimental: true 来启用实验模式。

默认情况下,实验模式是禁用的。要查看 Docker 守护进程的当前配置,请使用 docker version 命令并检查 Engine 部分中的 Experimental

Client: Docker Engine - Community
 Version:           23.0.3
 API version:       1.42
 Go version:        go1.19.7
 Git commit:        3e7cbfd
 Built:             Tue Apr  4 22:05:41 2023
 OS/Arch:           darwin/amd64
 Context:           default

Server: Docker Engine - Community
 Engine:
  Version:          23.0.3
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.19.7
  Git commit:       59118bf
  Built:            Tue Apr  4 22:05:41 2023
  OS/Arch:          linux/amd64
  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

接下来,使用 --squash 标志构建名为 test 的镜像。

$ docker build --squash -t test .

构建完成后,历史记录如下所示。历史记录可能会显示一个层的名称是 <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

测试镜像,检查 /remove_me 是否已移除,确保 hello\nworld/hello 中,确保环境变量 HELLO 的值是 world