docker构建缓存以“层”为基本单位,每条dockerfile指令生成一层;某层变更则其后所有层均需重建,故应将稳定操作(如依赖安装)前置、频繁变更操作(如源码复制)后置,并借助arg扰动、.dockerignore过滤及多阶段构建精准控制缓存失效。

理解Docker构建缓存,关键在于明白“层”是缓存的基本单位。每条Dockerfile指令生成一层,只要该层内容没变,Docker就直接复用;一旦某层变了,它之后所有层都会重建——这直接影响构建速度和CI/CD效率。
分层顺序决定缓存是否生效
把变动少的操作放在前面,变动频繁的放后面,能大幅提升缓存命中率。比如依赖文件比源码稳定得多,应优先复制并安装:
- COPY package.json . && RUN npm install(或 COPY go.mod go.sum . && go mod download)
- 再 COPY . . 才复制全部源码
这样改了业务代码不会触发重装依赖,构建时间明显缩短。
精准控制缓存失效时机
有时需要主动刷新某一层,又不想全量重建。可用 ARG 配合时间戳或版本号扰动缓存:
- 在 Dockerfile 中写:ARG CACHE_BUST=1 && COPY ./src ./app
- 构建时传参:docker build --build-arg CACHE_BUST=$(date +%s) -t app:latest .
每次构建参数不同,COPY 这一层就强制更新,后续层仍可缓存。
避免构建上下文污染缓存
构建上下文(即 docker build . 的那个点)里任何文件变动,哪怕只是加了个日志文件,只要 COPY . . 出现在早期,就会让后续所有层失效。解决办法有二:
- 用 .dockerignore 排除无关文件(如 .git、node_modules、*.log)
- 拆分 COPY 指令,只复制真正需要的文件,不一股脑全拷贝
多阶段构建进一步隔离缓存影响
构建阶段和运行阶段完全分离,彼此缓存互不干扰。例如 Go 项目:
- builder 阶段:FROM golang,COPY + go build,产出二进制
- runner 阶段:FROM alpine,COPY --from=builder /app/main .,轻量启动
源码改动只影响 builder 阶段,runner 阶段只要二进制没变,就稳稳复用缓存。











