构建上下文
和docker build
命令从Dockerfile和上下文docker buildx build
构建 Docker 映像
。
什么是构建上下文?
构建上下文是您的构建可以访问的文件集。传递给构建命令的位置参数指定要用于构建的上下文:
$ docker build [OPTIONS] PATH | URL | -
^^^^^^^^^^^^^^
您可以传递以下任何输入作为构建的上下文:
- 本地目录的相对或绝对路径
- Git 存储库、tarball 或纯文本文件的远程 URL
docker build
通过标准输入通过管道传输到命令的纯文本文件或 tarball
文件系统上下文
当您的构建上下文是本地目录、远程 Git 存储库或 tar 文件时,它将成为构建器在构建期间可以访问的文件集。诸如COPY
和 之类的构建指令ADD
可以引用上下文中的任何文件和目录。
文件系统构建上下文是递归处理的:
- 当您指定本地目录或 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 作为构建上下文docker 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 .
来自标准输入的 Dockerfile 的本地上下文
使用以下语法使用本地文件系统上的文件构建映像,同时使用标准输入中的 Dockerfile。
$ docker build -f- <PATH>
该语法使用 -f(或 --file)选项指定要使用的 Dockerfile,并使用连字符 (-) 作为文件名来指示 Docker 从 stdin 读取 Dockerfile。
以下示例使用当前目录 (.) 作为构建上下文,并使用通过 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 传递给构建命令时,构建会使用 tarball 的内容作为文件系统上下文。
例如,给定以下项目目录:
.
├── Dockerfile
├── Makefile
├── README.md
├── main.c
├── scripts
├── src
└── test.Dockerfile
您可以创建目录的 tarball 并将其通过管道传输到构建以用作上下文:
$ tar czf foo.tar.gz *
$ docker build - < foo.tar.gz
构建从 tarball 上下文中解析 Dockerfile。您可以使用该
--file
标志来指定 Dockerfile 相对于 tarball 根目录的名称和位置。test.Dockerfile
在 tarball 中使用以下命令进行构建:
$ docker build --file test.Dockerfile - < foo.tar.gz
远程上下文
您可以指定远程 Git 存储库、tarball 或纯文本文件的地址作为构建上下文。
如果远程 tarball 是文本文件,则构建器不会收到 filesystem context,而是假设远程文件是 Dockerfile。请参阅 清空构建上下文。
Git 存储库
当您将指向 Git 存储库位置的 URL 作为参数传递给 时docker build
,构建器将使用该存储库作为构建上下文。
构建器执行存储库的浅层克隆,仅下载 HEAD 提交,而不是整个历史记录。
构建器递归地克隆存储库及其包含的任何子模块。
$ docker build https://github.com/user/myrepo.git
默认情况下,构建器会克隆您指定的存储库的默认分支上的最新提交。
网址片段
您可以将 URL 片段附加到 Git 存储库地址,以使构建器克隆存储库的特定分支、标签和子目录。
URL 片段的格式为#ref:dir
,其中:
ref
是分支、标签或远程引用的名称dir
是存储库内的子目录
例如,以下命令使用container
分支以及docker
该分支中的子目录作为构建上下文:
$ docker build https://github.com/user/myrepo.git#container:docker
下表列出了所有有效的后缀及其构建上下文:
构建语法后缀 | 提交已使用 | 构建使用的上下文 |
---|---|---|
myrepo.git | refs/heads/<default branch> | / |
myrepo.git#mytag | refs/tags/mytag | / |
myrepo.git#mybranch | refs/heads/mybranch | / |
myrepo.git#pull/42/head | refs/pull/42/head | / |
myrepo.git#:myfolder | refs/heads/<default branch> | /myfolder |
myrepo.git#master:myfolder | refs/heads/master | /myfolder |
myrepo.git#mytag:myfolder | refs/tags/mytag | /myfolder |
myrepo.git#mybranch:myfolder | refs/heads/mybranch | /myfolder |
保留 .git 目录
.git
默认情况下,BuildKit在使用 Git 上下文时不保留目录。您可以通过设置BUILDKIT_CONTEXT_KEEP_GIT_DIR
build 参数来配置 BuildKit 以保留该目录
。如果您想在构建期间检索 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 或基于令牌的身份验证。
如果您指定的 Git 上下文是 SSH 或 Git 地址,Buildx 会自动检测并使用 SSH 凭据。默认情况下,这使用$SSH_AUTH_SOCK
.您可以配置 SSH 凭据以与
--ssh
flag一起使用。
$ docker buildx build --ssh default git@github.com:user/private.git
--secret
如果您想使用基于令牌的身份验证,则可以使用flag传递令牌
。
$ GIT_AUTH_TOKEN=<token> docker buildx build \
--secret id=GIT_AUTH_TOKEN \
https://github.com/user/private.git
笔记
不要用于
--build-arg
秘密。
来自标准输入的 Dockerfile 的远程上下文
使用以下语法使用本地文件系统上的文件构建映像,同时使用标准输入中的 Dockerfile。
$ docker build -f- <URL>
该语法使用 -f(或 --file)选项指定要使用的 Dockerfile,并使用连字符 (-) 作为文件名来指示 Docker 从 stdin 读取 Dockerfile。
当您想要从不包含 Dockerfile 的存储库构建映像的情况下,这可能很有用。或者,如果您想使用自定义 Dockerfile 进行构建,而不需要维护自己的存储库分支。
以下示例使用来自 stdin 的 Dockerfile 构建映像,并添加来自 GitHub 上的hello-worldhello.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 上下文或远程构建器,则它不一定与您发出构建命令的计算机相同。 BuildKit 获取context.tar.gz
并将其用作构建上下文。 Tarball 上下文必须是符合标准 Unix 格式的 tar 存档,并且可以使用、或(
无压缩)格式tar
中的任何一种进行压缩。xz
bzip2
gzip
identity
空上下文
当您使用文本文件作为构建上下文时,构建器会将该文件解释为 Dockerfile。使用文本文件作为上下文意味着构建没有文件系统上下文。
当您的 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 指令无法
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
这有助于避免向构建器发送不需要的文件和目录,从而提高构建速度,尤其是在使用远程构建器时。
文件名和位置
.dockerignore
当您运行构建命令时,构建客户端会查找上下文根目录中命名的文件
。如果此文件存在,则在将其发送到构建器之前,将从构建上下文中删除与文件中的模式匹配的文件和目录。
如果您使用多个 Dockerfile,则可以为每个 Dockerfile 使用不同的忽略文件。您可以使用忽略文件的特殊命名约定来执行此操作。将忽略文件与 Dockerfile 放在同一目录中,并使用 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 的忽略文件优先于.dockerignore
构建上下文根目录中的文件。
句法
该.dockerignore
文件是一个以换行符分隔的模式列表,类似于 Unix shell 的文件 glob。为了匹配的目的,上下文的根被视为工作目录和根目录。例如,模式/foo/bar
和都排除在位于 的 Git 存储库的子目录或根目录中foo/bar
命名的文件或目录。两者都不排除其他任何东西。bar
foo
PATH
URL
.dockerignore
如果文件中的一行以#
第 1 列开头,则该行将被视为注释,并在由 CLI 解释之前被忽略。
如果您有兴趣了解模式匹配逻辑的精确细节.dockerignore
,请查看
GitHub 上的moby/patternmatcher 存储库
,其中包含源代码。
匹配
以下代码片段显示了一个示例.dockerignore
文件。
# comment
*/temp*
*/*/temp*
temp?
该文件会导致以下构建行为:
规则 | 行为 |
---|---|
# comment | 被忽略了。 |
*/temp* | temp 排除名称以根目录的任何直接子目录开头的文件和目录。例如,纯文件/somedir/temporary.txt 被排除,目录也被排除/somedir/temp 。 |
*/*/temp* | temp 排除从根以下两级的任何子目录开始的文件和目录。例如,/somedir/subdir/temporary.txt 被排除。 |
temp? | 排除根目录中名称为单字符扩展名temp .例如,/tempa 和/tempb 被排除在外。 |
匹配是使用 Go 的
filepath.Match
函数规则完成的。预处理步骤使用 Go 的
filepath.Clean
函数
来修剪空格并删除.
和..
。预处理后的空白行将被忽略。
笔记
由于历史原因,该模式
.
被忽略。
除了 Go 的filepath.Match
规则之外,Docker 还支持特殊的通配符字符串**
,可以匹配任意数量的目录(包括零)。例如,排除在构建上下文中**/*.go
以 find 结尾的所有文件。.go
您可以使用该.dockerignore
文件来排除Dockerfile
和
.dockerignore
文件。这些文件仍会发送到构建器,因为运行构建需要它们。但您无法使用 、 或绑定安装将文件复制到映像
ADD
中COPY
。
否定匹配
您可以在行前面添加!
(感叹号)以排除例外。以下是.dockerignore
使用此机制的示例文件:
*.md
!README.md
上下文目录下的所有 Markdown 文件都从上下文中排除。 README.md
请注意,子目录下的 markdown 文件仍然包含在内。
例外规则的放置会影响行为:与特定文件匹配!
的最后一行确定是否包含或排除该文件。.dockerignore
考虑以下示例:
*.md
!README*.md
README-secret.md
除了 .README 文件之外,上下文中不包含任何 Markdown 文件
README-secret.md
。
现在考虑这个例子:
*.md
README-secret.md
!README*.md
包含所有自述文件。中间的线没有任何作用,因为
!README*.md
匹配README-secret.md
并且排在最后。