.dockerignore 速查表 - Docker 构建上下文忽略规则大全
写 Dockerfile 时若漏配 .dockerignore,docker build . 会把 node_modules、.git 整个打包进构建上下文,拖慢构建还虚增镜像体积。这份速查覆盖 5 组:基础语法、通配符、常见忽略项、与 .gitignore 的差异,以及瘦身技巧。写出模板后用 docker build 验证上下文大小,误删文件时记住 ! 取反只会对已被忽略的项生效。读完后你能为项目配一份安全且精简的 .dockerignore。
基础语法 Basic Syntax 5
node_modules*.logtmp/**/tmp# comment通配符 Glob 6
*?**[abc]*.tmpdist/*常见忽略项 Common Ignores 6
.gitnode_modules.envDockerfile*.md.dockerignore与 .gitignore 差异 4
!node_modules/importantDockerfile 不读 .gitignore构建上下文 = docker build .COPY 仍受路径限制瘦身技巧 Slimming 4
**/*.pyc.cache/coverage/tests/命令示例
一份够用的基础模板
.git
node_modules
.env
*.log
**/*.pyc
.cache/
coverage/
tests/前四行覆盖版本库、依赖、密钥与日志,是最常被漏掉也最危险的几类;后四行是瘦身项,其中 **/*.pyc 跨所有层级匹配编译缓存,带斜杠的 .cache/ 只限定根目录。
通配符三种写法的实际含义
*.log
tmp/
**/tmp
dist/**.log 匹配任意层级的 .log 文件;tmp/ 只排除根下那一个目录;**/tmp 排除所有层级的 tmp;dist/* 只排除 dist 下一层内容而保留 dist 目录本身,目录是否需要保留决定了该用哪种。
取反重新包含:位置决定是否生效
node_modules
!node_modules/important取反必须写在忽略规则之后,因为规则从上往下匹配、后写的覆盖先写的。这里的效果是整个 node_modules 不进上下文,但其中 important 目录被重新包含进来。
与 .gitignore 的边界:三条容易记混的事实
# comment
.dockerignore井号起头是注释,空行直接忽略;忽略自身不影响当前构建但少了它就无法在镜像里查规则。Docker 不读 .gitignore,两份文件必须各写一份。
常见坑与注意事项
- .dockerignore 只影响送进构建上下文的内容,不限制 COPY 的目标路径,别把它当成 Dockerfile 路径安全的一部分。
- 用 ! 取反前必须确认该路径已被前面的规则忽略过;没有被忽略的路径写取反是空操作,不会让它进包。
- .env 一旦进入上下文就会留在镜像层里,即使后续删除文件也删不掉那一层;密钥类文件必须从一开始就在忽略列表里。
- dist/* 保留目录本身、dist/** 会连目录一起排除,需要保留空目录做挂载点时别选错写法。
- .dockerignore 与 .gitignore 互相独立,把同一份文件复制过去当共用是最常见的失效原因。
提示
- 不配 .dockerignore 时,docker build . 会把当前目录全部发给 daemon,node_modules 和 .git 会让上下文巨大。
- 带斜杠的 tmp/ 只匹配根目录 tmp,不带斜杠的 tmp 会匹配任意层级的 tmp。
- .dockerignore 与 .gitignore 互不影响,不能共用同一份文件。
- 用 ** 可跨层级匹配目录,如 **/__pycache__ 忽略所有 Python 缓存。
常见问题
不配 .dockerignore,docker build . 到底会传什么?
当前目录的全部内容,一个字节不过滤。构建上下文是整个目录树原样交给 daemon,忽略只发生在 .dockerignore 列出的条目上。所以一个没配任何忽略规则的仓库会把 .git 历史、node_modules、构建产物、本地日志甚至 .env 一起打包发送——构建变慢只是后果之一,更严重的是密钥被打进镜像层,即使后续删掉文件,层本身仍然留在镜像里。正确做法是从模板起步,先覆盖依赖目录、版本库与本地配置三类。
tmp/ 和 **/tmp 有什么区别?
带不带路径分隔符决定了匹配是否限定在根目录。tmp/ 带尾斜杠,只匹配构建上下文根下的那一个 tmp 目录;不带斜杠的 tmp 会匹配任意层级的同名文件或目录。**/tmp 则是显式的跨层级写法,语义上等价于不加斜杠的 tmp,但在多层嵌套的项目里可读性更好,也更容易让人一眼看出「我要忽略所有层级」。选择依据是意图:只想排除构建根下的临时产物就用 tmp/,想让任何位置的同名目录都不进包就用不带斜杠或 ** 的形式。
.dockerignore 和 .gitignore 能共用一份吗?
不能,两者语法相近但语义不同,各管各的。.gitignore 管的是版本库,.dockerignore 管的是构建上下文;Docker 不会读取 .gitignore,反之亦然,所以写一份就等于另一半场景完全失效。实践中的差别体现在取反语法上:! 可以重新包含被忽略的项,但它只能对已经被规则忽略的路径生效——如果前面没有任何规则忽略过它,这条取反就是空操作。
用 ! 取反重新包含某个文件,为什么没生效?
几乎总是因为取反写在了前面,或者没有前置规则命中过它。取反是「撤销已有忽略」,不是「显式包含」:如果 .env 本身从未出现在忽略列表里,!.env 就是一句多余的话;而如果先写了忽略规则、后面又用忽略规则把它重新盖回去,取反同样失效。规则按从上到下顺序匹配、后者覆盖前者,所以要取反的条目必须放在忽略它的规则之后。另外注意取反只会影响发送进上下文的内容,不会放开 COPY 的路径限制。
配好 .dockerignore 后怎么确认生效了?
看构建输出里传输上下文的那一步,或用构建镜像历史确认体积。排除规则多时最常见的错误是写法看似正确但层级没对上,于是文件仍在包里——所以每次改动后都重新构建一次,比凭记忆判断可靠。体积层面用 docker history 逐层看体积,定位是哪一层带进来的大文件,再回头补规则。经验上把 .git、依赖目录、本地配置、测试与覆盖率产物、缓存目录这几类先覆盖掉,剩余按需再加。
由 巧匠 维护
公开更新于 2026年8月2日,内容持续校对官方文档。