一文看懂 .dockerignore

dockerfile 同级目录中创建名为 .dockerignore 的文件,用法与 .gitignore 类似,可以实现在构建镜像的时,不将某些文件夹或文件打入到镜像中。

以下示例会过滤 images、media 目录,以及 png、jpg 图片。

  • .dockerignore
*/images/
*/media/
*.png
*.jpg
1
2
3
4

我们来看下这个示例,首先看下 dockerfile ADD 的内容,重点是 ADD book/docs/.vuepress/dist/ /usr/share/nginx/html/ 这一行。

  • dockerfile
FROM nginx:alpine
WORKDIR /usr/share/nginx/html
ADD book/docs/.vuepress/dist/ /usr/share/nginx/html/
ADD etc/nginx/nginx.conf /etc/nginx/nginx.conf
ADD etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf
ADD etc/localtime /etc/localtime
EXPOSE 80
1
2
3
4
5
6
7

这是 book/docs/.vuepress/dist/other/else/ 的目录结构,包含一个 media 文件夹

~$ ll other/else/
total 16
-rw-r--r--@ 1 spark  staff   1.6K  8  1 16:15 enable-1000mbps.md
-rw-r--r--@ 1 spark  staff   1.8K  7 27 17:57 max-values-per-tag.md
drwxr-xr-x@ 8 spark  staff   256B  8  1 16:11 media
1
2
3
4
5

这是构建镜像后,运行容器并查看 other/else 目录的结构,可以看到其下没有 media 目录,已经被排除了。

~$ docker exec a95e5556c87c pwd
/usr/share/nginx/html
~$ docker exec a95e5556c87c ls -lh other/else
total 68K
-rw-r--r--    1 root     root       31.6K Aug  1 16:20 enable-1000mbps.html
-rw-r--r--    1 root     root       32.5K Aug  1 16:20 max-values-per-tag.html
~$
1
2
3
4
5
6
7

看完示例,接下来我们翻译一下 Docker 官方的 .dockerignoreopen in new window 的文档,不是硬翻译,带了自己的理解。

.dockerignore 详细介绍

在 docker build 过程中,Docker CLI 将 context 发送到 docker 守护进程之前,它会查看根目录中名为 .dockerignore 的文件。

如果 .dockerignore 存在,Docker CLI 将修改 context 以排除文件和目录。

这样可以将不必要的文件不打入到 Docker 镜像中,让 docker 镜像保持干净。

Docker CLI 将 .dockerignore 文件解释为换行符分隔的文件,也就是一行一个匹配规则。

context 的根目录为项目的根目录,也就是 dockerfile 的同级目录。你可以使用 / 开头的绝对路径,也可以使用相对路径。 比如 /foo/barfoo/bar 效果是一样的。

.dockerignore 中,# 开头的行被认为是注释。

下面是一个 .dockerignore 文件示例:

# 注释
*/temp*
*/*/temp*
temp?
1
2
3
4

以下是对该 .dockerignore 文件的解释:

匹配规则匹配结果
# comment忽略
*/temp*排除根目录中(也就是不包含子目录)目录名称以 temp 开头的文件和目录。例如,排除普通文件 /somedir/temporary.txt,目录 /somedir/temp
*/*/temp*排除根目录的二级子目录中以 temp 开头的文件和目录。例如,排除 /somedir/subdir/temporary.txt
temp?排除根目录中名称以 temp 开头,外加一个字符的文件和目录。例如,排除 /tempa/tempb

匹配规则引用了 Go 的 filepath.Matchopen in new window 规则。预处理步骤会删除一行中首尾空格,同时使用 filepath.Cleanopen in new window 会忽略 ... 。预处理(preprocessing)后为空的行将被忽略。

除了 Go 的 filepath.Match 规则,Docker 还支持一个特殊的通配符字符串 ** 匹配任意数量的目录(包括零)。例如,**/*.go 将排除所有目录中以 .go 结尾的文件,包含根目录。

!(感叹号)开头的行用来做例外,也就是说这些行不会被排除,仍然会打入到镜像中。以下是一个 .dockerignore 示例:

*.md
!README.md
1
2

除了 README.md, 所有 Markdown 文件都将排除。

! 异常规则的位置会影响匹配结果:包含指定文件(例如下文示例中的 README-secret.md 匹配的 .dockerignore 的最后一行确定是包含还是排除该文件。看一下这个例子:

*.md
!README*.md
README-secret.md
1
2
3

context 中不包含任何 Markdown 文件,除了 README 开头的 mdREADME-secret.md文件。

现在我们看下这个例子:

*.md
README-secret.md
!README*.md
1
2
3

context 中包含 README-secret.md 在内的所有 README 文件,不包含剩下 Markdown 文件。README-secret.md 没有被排除,因为 !README*.md 包含 README-secret.md 并且 !README*.md在最后。

你甚至可以使用 .dockerignore 文件来排除 Dockerfile.dockerignore 文件。这些文件仍然发送到 Deamon 进程,但 ADDCOPY 指令不会将它们复制到镜像中。

最后,您可能希望指定要包含在 context 中,而不是排除哪个。为此,请将 * 放在第一行,后跟一个或多个 ! 异常模式。

** 注意事项 **

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

reference