docker构建提速关键在于精准控制缓存命中:按“稳定→易变”排序指令(如先copy依赖文件再copy源码),严格管控构建上下文(用.dockerignore排除冗余文件),并在ci中通过buildx配置registry缓存或cache mounts实现跨节点复用。
要让 docker 构建真正快起来,关键不是堆硬件或换工具,而是吃透缓存怎么“认人”——它只复用完全一致的层,差一个空格、一行注释、甚至文件时间戳,都可能让整条流水线从头来过。核心就三点:分层顺序合理、上下文干净、缓存路径明确。
分层顺序决定缓存命中的生死线
Docker 每一层都依赖前一层的哈希值。一旦某层失效,后面所有层全得重做。所以必须把最稳定的操作放前面,最易变的放最后:
- 先 COPY go.mod / package.json / requirements.txt 这类锁定文件,再 RUN 安装依赖——只要依赖没变,这一步永远命中缓存
- 再 COPY 源码(COPY . . 或 COPY src/ ./src)——代码天天改,放这儿才不会拖累前面的依赖层
- 避免在 COPY 之前写 ENV 或 WORKDIR 以外的 RUN 指令,尤其是涉及网络或生成内容的操作
构建上下文必须轻量且可控
docker build 开始前会把整个上下文打包上传。如果里面塞了 node_modules、.git、日志或大文件,光“Sending build context”就能卡半分钟:
- 务必配好 .dockerignore:至少包含
node_modules、.git、*.log、npm-debug.log、Dockerfile、.dockerignore - 不要用
COPY .. .或COPY . .向上越级复制;用最小必要路径,比如COPY src/ ./src - CI 环境中可提前清理构建目录,或用
git archive生成纯净源码包作为上下文
Buildx 缓存卷是 CI 场景的刚需配置
原生 docker build 的缓存只在单机本地有效,CI 流水线每次都是新环境。Buildx 的 cache mounts 才能跨构建、跨节点复用中间产物:
- 对 Node.js 项目,挂载 npm 缓存:
--mount=type=cache,id=npm-cache,target=/root/.npm - 对 Go 项目,同时挂载模块和构建缓存:
--mount=type=cache,id=go-mod,target=/go/pkg/mod --mount=type=cache,id=go-build,target=/root/.cache/go-build - 生产 CI 推荐用 registry 缓存:用
--cache-to type=registry,ref=reg.example.com/myapp:buildcache把缓存推到镜像仓库,下次构建直接--cache-from拉取
多阶段构建不是为了减体积,而是为缓存服务
很多人以为多阶段只为瘦身,其实它更大的价值是隔离构建逻辑,让每个阶段的缓存更独立、更稳定:
- builder 阶段专注编译:FROM golang:1.21 → COPY go.* → RUN go mod download → COPY . . → RUN go build
- runtime 阶段只拿结果:FROM alpine → COPY --from=builder /app/main . → CMD ["./main"]
- 这样即使 runtime 镜像基础层升级(如 alpine:3.20 → 3.21),builder 阶段的依赖下载和编译仍可复用旧缓存











