构建上下文

和 命令从中构建 Docker 镜像 一个 Dockerfile 和一个上下文。docker builddocker buildx build

什么是构建上下文?

构建上下文是构建可以访问的一组文件。 传递给 build 命令的 positional 参数指定 context 中:

$ docker build [OPTIONS] PATH | URL | -
                         ^^^^^^^^^^^^^^

您可以将以下任何输入作为构建的上下文传递:

  • 本地目录的相对或绝对路径
  • Git 存储库、tarball 或纯文本文件的远程 URL
  • 通过标准输入通过管道传输到命令的纯文本文件或 tarballdocker build

文件系统上下文

当您的构建上下文是本地目录、远程 Git 存储库或 tar 时 文件,则它将成为生成器可以在 建。构建指令(如 和 )可以引用任何 文件中的文件和目录。COPYADD

文件系统构建上下文以递归方式处理:

  • 当您指定本地目录或 tarball 时,所有子目录都包含在内
  • 指定远程 Git 存储库时,将包含存储库和所有子模块

有关您 可以与你的版本一起使用,请参阅:

文本文件上下文

当您的构建上下文是纯文本文件时,构建器会解释该文件 作为 Dockerfile 进行。使用这种方法,构建不使用文件系统上下文。

有关更多信息,请参阅空构建上下文

本地上下文

要使用本地构建上下文,您可以指定相对或绝对文件路径 添加到命令中。以下示例显示了一个生成命令,该命令 使用当前目录 () 作为构建上下文:docker build.

$ docker build .
...
#16 [internal] load build context
#16 sha256:23ca2f94460dcbaf5b3c3edbaaa933281a4e0ea3d92fe295193e4df44dc68f85
#16 transferring context: 13.16MB 2.2s done
...

这使得当前工作目录中的文件和目录可供 构建器。在以下情况下,构建器会从构建上下文中加载所需的文件 需要。

你也可以使用本地 tarball 作为构建上下文,方法是将 tarball 管道化 contents 添加到命令中。参见 Tarballsdocker build

本地目录

请考虑以下目录结构:

.
├── index.ts
├── src/
├── Dockerfile
├── package.json
└── package-lock.json

如果 Dockerfile 指令可以引用这些文件并将其包含在构建中,则 将此目录作为上下文传递。

# syntax=docker/dockerfile:1
FROM node:latest
WORKDIR /src
COPY package.json package-lock.json .
RUN npm ci
COPY index.ts src .
$ docker build .

带有 stdin 的 Dockerfile 的本地上下文

使用以下语法使用本地 filesystem,同时使用 stdin 中的 Dockerfile。

$ docker build -f- <PATH>

语法使用 -f(或 --file)选项来指定要使用的 Dockerfile,并且 它使用连字符 (-) 作为文件名,指示 Docker 从 stdin 的

以下示例使用当前目录 (.) 作为构建上下文,并且 使用 here-document 通过 stdin 传递的 Dockerfile 构建镜像。

# create a directory to work in
mkdir example
cd example

# create an example file
touch somefile.txt

# build an image using the current directory as context
# and a Dockerfile passed through stdin
docker build -t myimage:latest -f- . <<EOF
FROM busybox
COPY somefile.txt ./
RUN cat /somefile.txt
EOF

本地 tarball

当您通过管道将 tarball 传递给 build 命令时,构建使用 将 tarball 作为 filesystem 上下文。

例如,给定以下项目目录:

.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile

您可以创建目录的 tarball 并将其通过管道传输到构建中,以用作 上下文:

$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz

构建从 tarball 上下文解析 Dockerfile。您可以使用该标志指定 Dockerfile 的名称和位置,相对于 tarball 的根。以下命令在 tarball 中构建 using:--filetest.Dockerfile

$ docker build --file test.Dockerfile - < foo.tar.gz

远程上下文

您可以指定远程 Git 存储库、tarball 或纯文本的地址 file 作为您的构建上下文。

  • 对于 Git 存储库,生成器会自动克隆存储库。请参阅 Git 存储库
  • 对于 tarball,构建器会下载并提取 tarball 的内容。 参见 Tarballs

如果远程 tarball 是一个文本文件,则构建器不会收到任何文件系统 context,而是假设远程 file 是一个 Dockerfile。请参阅 空构建上下文

Git 存储库

当您将指向 Git 存储库位置的 URL 作为参数传递时 到 ,生成器使用存储库作为构建上下文。docker build

构建器执行存储库的浅层克隆,仅下载 HEAD 提交,而不是整个历史记录。

构建器以递归方式克隆存储库及其包含的任何子模块。

$ docker build https://github.com/user/myrepo.git

默认情况下,构建器会在 存储库。

URL 片段

您可以将 URL 片段附加到 Git 存储库地址,以使构建器 克隆存储库的特定分支、标签和子目录。

URL 片段的格式为 ,其中:#ref:dir

  • ref是分支、标签或提交哈希的名称
  • dir是存储库中的子目录

例如,以下命令使用分支 和该分支中的子目录作为构建上下文:containerdocker

$ docker build https://github.com/user/myrepo.git#container:docker

下表显示了所有有效的后缀及其内部版本 上下文:

生成语法后缀已使用的提交使用的构建上下文
myrepo.gitrefs/heads/<default branch>/
myrepo.git#mytagrefs/tags/mytag/
myrepo.git#mybranchrefs/heads/mybranch/
myrepo.git#pull/42/headrefs/pull/42/head/
myrepo.git#:myfolderrefs/heads/<default branch>/myfolder
myrepo.git#master:myfolderrefs/heads/master/myfolder
myrepo.git#mytag:myfolderrefs/tags/mytag/myfolder
myrepo.git#mybranch:myfolderrefs/heads/mybranch/myfolder

当您使用提交哈希作为 URL 片段中时,请使用完整的 提交的 40 个字符的字符串 SHA-1 哈希。短哈希值,例如哈希值 truncated 为 7 个字符。ref

# ✅ The following works:
docker build github.com/docker/buildx#d4f088e689b41353d74f1a0bfcd6d7c0b213aed2
# ❌ The following doesn't work because the commit hash is truncated:
docker build github.com/docker/buildx#d4f088e

保留 .git 目录

默认情况下,BuildKit 在使用 Git 上下文时不保留目录。 你可以通过设置 BUILDKIT_CONTEXT_KEEP_GIT_DIR build 参数来配置 BuildKit 保留目录。 如果您想在构建过程中检索 Git 信息,这可能很有用:.git

# syntax=docker/dockerfile:1
FROM alpine
WORKDIR /src
RUN --mount=target=. \
  make REVISION=$(git rev-parse HEAD) build
$ docker build \
  --build-arg BUILDKIT_CONTEXT_KEEP_GIT_DIR=1
  https://github.com/user/myrepo.git#main

私有仓库

当您指定同时也是私有存储库的 Git 上下文时,构建器 需要您提供必要的身份验证凭证。您可以使用 SSH 或基于令牌的身份验证。

Buildx 会自动检测并使用 SSH 凭据,如果 Git 上下文 specify 是 SSH 或 Git 地址。默认情况下,它使用 . 您可以配置要与 --ssh 标志一起使用的 SSH 凭证。$SSH_AUTH_SOCK

$ docker buildx build --ssh default git@github.com:user/private.git

如果要改用基于令牌的身份验证,则可以传递令牌 使用 --secret 标志

$ GIT_AUTH_TOKEN=<token> docker buildx build \
  --secret id=GIT_AUTH_TOKEN \
  https://github.com/user/private.git

注意

不要用于机密。--build-arg

使用 stdin 中的 Dockerfile 的远程上下文

使用以下语法使用本地 filesystem,同时使用 stdin 中的 Dockerfile。

$ docker build -f- <URL>

语法使用 -f(或 --file)选项来指定要使用的 Dockerfile,并且 它使用连字符 (-) 作为文件名,指示 Docker 从 stdin 的

这在您想要从 不包含 Dockerfile 的存储库。或者,如果您想使用 自定义 Dockerfile,而无需维护您自己的存储库分支。

以下示例使用 stdin 中的 Dockerfile 构建镜像,并将 GitHub 上 hello-world 存储库中的文件。hello.c

docker build -t myimage:latest -f- https://github.com/docker-library/hello-world.git <<EOF
FROM busybox
COPY hello.c ./
EOF

远程 tarball

如果您将 URL 传递给远程 tarball,则 URL 本身将发送到构建器。

$ docker build http://server/context.tar.gz
#1 [internal] load remote build context
#1 DONE 0.2s

#2 copy /context /
#2 DONE 0.1s
...

下载操作将在 BuildKit 守护程序 正在运行。请注意,如果您使用的是远程 Docker 上下文或远程 builder 的 build 文件,它不一定与您发布 build 的计算机相同 命令。BuildKit 获取 并将其用作构建 上下文。Tarball 上下文必须是符合标准 Unix 格式的 tar 存档,并且可以使用 、 或 (无压缩) 格式中的任何一种进行压缩。context.tar.gztarxzbzip2gzipidentity

空上下文

当您使用文本文件作为构建上下文时,构建器会解释该文件 作为 Dockerfile 进行。使用文本文件作为上下文意味着构建没有 filesystem 上下文。

当 Dockerfile 不依赖时,您可以使用空的构建上下文进行构建 在任何本地文件上。

如何在没有上下文的情况下构建

您可以使用标准输入流传递文本文件,也可以通过指向 远程文本文件的 URL。


$ docker build - < Dockerfile
Get-Content Dockerfile | docker build -
docker build -t myimage:latest - <<EOF
FROM busybox
RUN echo "hello world"
EOF
$ docker build https://raw.githubusercontent.com/dvdksn/clockbox/main/Dockerfile

在没有文件系统上下文的情况下进行构建时,Dockerfile 指令(例如 can't refer to local files):COPY

$ ls
main.c
$ docker build -<<< $'FROM scratch\nCOPY main.c .'
[+] Building 0.0s (4/4) FINISHED
 => [internal] load build definition from Dockerfile       0.0s
 => => transferring dockerfile: 64B                        0.0s
 => [internal] load .dockerignore                          0.0s
 => => transferring context: 2B                            0.0s
 => [internal] load build context                          0.0s
 => => transferring context: 2B                            0.0s
 => ERROR [1/1] COPY main.c .                              0.0s
------
 > [1/1] COPY main.c .:
------
Dockerfile:2
--------------------
   1 |     FROM scratch
   2 | >>> COPY main.c .
   3 |
--------------------
ERROR: failed to solve: failed to compute cache key: failed to calculate checksum of ref 7ab2bb61-0c28-432e-abf5-a4c3440bc6b6::4lgfpdf54n5uqxnv9v6ymg7ih: "/main.c": not found

.dockerignore 文件

您可以使用文件从 构建上下文。.dockerignore

# .dockerignore
node_modules
bar

这有助于避免将不需要的文件和目录发送给构建器。 提高构建速度,尤其是在使用远程构建器时。

文件名和位置

当您运行构建命令时,构建客户端会查找在上下文的根目录中命名的文件。如果此文件存在,则 与文件中的模式匹配的文件和目录将从 build 上下文。.dockerignore

如果您使用多个 Dockerfile,则可以为每个 Dockerfile 使用不同的 ignore-files Dockerfile 文件。为此,请使用 ignore-files 的特殊命名约定。 将 ignore-file 放在与 Dockerfile 相同的目录中,并在 ignore-file 替换为 Dockerfile 的名称,如以下示例所示。

.
├── index.ts
├── src/
├── docker
│   ├── build.Dockerfile
│   ├── build.Dockerfile.dockerignore
│   ├── lint.Dockerfile
│   ├── lint.Dockerfile.dockerignore
│   ├── test.Dockerfile
│   └── test.Dockerfile.dockerignore
├── package.json
└── package-lock.json

如果两者都存在,则特定于 Dockerfile 的 ignore-file 优先于构建上下文根目录中的文件。.dockerignore

语法

该文件是一个以换行符分隔的模式列表,类似于 文件 globs 的 Unix shell 的 Loms 文件。ignore 模式中的前导和尾部斜杠是 忽视。以下模式都排除了 build 上下文根目录下的子目录中命名的文件或目录:.dockerignorebarfoo

  • /foo/bar/
  • /foo/bar
  • foo/bar/
  • foo/bar

如果 file 中的一行以第 1 列开头,则此行 被视为注释,在被 CLI 解释之前被忽略。.dockerignore#

#/this/is/a/comment

如果您有兴趣了解模式匹配逻辑的确切细节,请查看 GitHub 上的 moby/patternmatcher 存储库,其中包含源代码。.dockerignore

匹配

以下代码片段显示了一个示例文件。.dockerignore

# comment
*/temp*
*/*/temp*
temp?

此文件会导致以下生成行为:

统治行为
# comment忽视。
*/temp*排除名称以根的任何直接子目录中开头的文件和目录。例如,plain 文件被排除在外,目录 .temp/somedir/temporary.txt/somedir/temp
*/*/temp*从根目录下两级的任何子目录中排除以 开头的文件和目录。例如,被排除。temp/somedir/subdir/temporary.txt
temp?排除根目录中名称为 .例如,和 are excluded。temp/tempa/tempb

匹配是使用 Go 的 filepath 完成的。匹配函数规则。 预处理步骤使用 Go 的 filepath。清理函数来修剪空格并删除 和 . 预处理后为空的行将被忽略。...

注意

由于历史原因,该模式被忽略。.

除了 Go 的规则之外,Docker 还支持特殊的通配符 匹配任意数量的目录(包括零)的字符串。为 example,排除以 found anywhere 结尾的所有文件。 构建上下文。filepath.Match****/*.go.go

您可以使用该文件排除 和 文件。这些文件仍按原样发送给生成器 运行构建所需的。但是,您不能使用 、 或 bind 挂载将文件复制到镜像中。.dockerignoreDockerfile.dockerignoreADDCOPY

否定匹配项

您可以在行前加上 (感叹号) 以例外 排除。下面是一个使用此 机制:!.dockerignore

*.md
!README.md

上下文目录下的所有 markdown 文件,除了 从上下文中排除。请注意,子目录下的 markdown 文件是 仍然包括在内。README.md

异常规则的位置会影响行为:最后一行 匹配特定文件的 () 确定它是否为 包含或排除。请考虑以下示例:!.dockerignore

*.md
!README*.md
README-secret.md

除了 README 文件以外的 .README-secret.md

现在考虑以下示例:

*.md
README-secret.md
!README*.md

包括所有 README 文件。中间线没有效果,因为 matches 和 comes last。!README*.mdREADME-secret.md