构建上下文
和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_DIRbuild 参数来配置 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 凭据以与
--sshflag一起使用。
$ 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
中的任何一种进行压缩。xzbzip2gzipidentity
空上下文
当您使用文本文件作为构建上下文时,构建器会将该文件解释为 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命名的文件或目录。两者都不排除其他任何东西。barfooPATHURL
.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并且排在最后。