bigywater.tech
Docker · 7

.dockerignore:忽略规则怎么影响上下文大小和缓存

.dockerignore 看起来只是“少传点文件”,但它同时决定了镜像里有什么、COPY 层的缓存能不能命中。它的匹配规则又不是 .gitignore 的那一套:`*.log` 只管根目录。这篇用一个故意塞满各种文件的目录,逐条验证规则的效果。

31.47 MB → 509 B
30 MiB 的 node_modules 加入 .dockerignore 前后,COPY 一步的传输量
只管根目录
`*.log` 和 `/build` 只匹配上下文根目录这一层,src/b.log 与 src/build/ 都没被忽略
取代而不是叠加
Dockerfile.dockerignore 存在时,.dockerignore 不再生效

不写会怎样

实测 · 本机执行输出
  退出码 0,用时 1625 ms,transferring context(COPY 一步)31.47MB
  镜像里 /app 有 11 个文件:./Dockerfile ./README.md ./build.log ./build/out.bin ./main.txt ./node_modules/big.bin ./notes.md ./src/a.txt ./src/b.log ./src/build/inner.txt ./tmp/x/y/temp

没有 .dockerignore,COPY . /app 把 30 MiB 的 node_modules、日志、构建产物全带进镜像,上下文传输 31.47 MB,构建 1625 ms。

规则逐条看

实测 · 本机执行输出
  .dockerignore 的内容:node_modules | *.log | /build | **/temp | *.md | !README.md
  退出码 0,用时 285 ms,transferring context(COPY 一步)509B
  镜像里 /app 有 7 个文件:./.dockerignore ./Dockerfile ./README.md ./main.txt ./src/a.txt ./src/b.log ./src/build/inner.txt
  被忽略的文件:./build.log ./build/out.bin ./node_modules/big.bin ./notes.md ./tmp/x/y/temp
  说明:`*.log` 只匹配根目录这一层的 build.log,src/b.log 没被忽略;`/build` 只匹配根目录的 build,src/build/inner.txt 没被忽略;`**/temp` 匹配任意深度;`*.md` 之后的 `!README.md` 把 README.md 加回来(后面的规则覆盖前面的)

写了 6 行规则后传输降到 509 B、285 ms:node_modules 与 **/temp 把目录整个忽略;*.md 之后的 !README.md 把 README 加回来(后面的规则覆盖前面的)。陷阱是 *.log 和 /build 只匹配根目录那一层,src/b.log、src/build/inner.txt 都还在镜像里。

任意深度要写 **

实测 · 本机执行输出
  忽略规则 **/*.log 之后镜像里还有的 log 文件:(没有)

**/*.log 才能忽略所有层级的 log。这和 .gitignore 的直觉不同,是最容易漏的地方。

缓存

实测 · 本机执行输出
  [不忽略 build.log] 只改了 build.log 后再构建:COPY 层 重新执行,用时 250 ms
  [忽略 build.log] 只改了 build.log 后再构建:COPY 层 命中缓存(CACHED),用时 235 ms

只改了 build.log:不忽略它时 COPY . /app 层要重新执行,忽略它时这一层命中缓存。把日志、构建输出、临时文件加进 .dockerignore,能让依赖 COPY . 的后续层不被无关变化打断。

Dockerfile 自己

实测 · 本机执行输出
  只有 .dockerignore(写了 Dockerfile、.dockerignore、b.txt):退出码 0;镜像里 /app 有 ['./a.txt']
  再加一个 Dockerfile.dockerignore(只写了 a.txt):退出码 0;镜像里 /app 有 ['./.dockerignore', './Dockerfile', './Dockerfile.dockerignore', './b.txt'](它取代了 .dockerignore,不是叠加)

把 Dockerfile 和 .dockerignore 写进规则,COPY . 不会把它们带进镜像(它们仍然会被发给构建器)。每个 Dockerfile 可以有自己的 Dockerfile.dockerignore,它存在时完全取代 .dockerignore,实验里原来的规则一条都没生效。

分步演示

.dockerignore
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。上下文含 os.urandom 生成的 30 MiB 文件;镜像里的文件用 docker run … find 列出;缓存命中通过构建输出里 COPY 步骤的 CACHED 判断;每种情形各一次;实验后已删除所有镜像和临时目录
    • 没有验证:.dockerignore 里更复杂的 Go filepath.Match 语法(如 ? 和 [] )、规则很多时的匹配成本、符号链接的处理、docker compose 的 build 上下文、Docker 文档里对规则的描述(本机没有这份文档,规则全部来自实测)
    京ICP备2026067502号-1京公网安备11010502063487号