Docker 构建应遵循缓存优化原则:变化少的指令靠前,基础镜像和系统依赖紧贴 FROM;固定标签、合并 RUN 指令、优先复制依赖文件、减少中间层冗余、多阶段构建分离编译与运行环境。

核心原则是:让变化少的指令靠前,变化频繁的靠后。Docker 构建缓存按层生效,一旦某层失效,它后面所有层都会重新构建。
基础镜像和系统依赖放最前面
FROM 和系统级安装(如 apt、apk)几乎不随业务迭代变动,必须紧贴开头。
- 用固定标签,比如 FROM ubuntu:22.04,别用 latest,避免上游镜像更新导致整条缓存链断裂
- 把 apt update、install、清理合并成一条 RUN 指令:RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
- 避免在 RUN 中调用带时间戳、随机数或网络请求的命令(如 date、curl API),它们每次生成不同哈希,强制缓存失效
依赖文件先于源码复制
依赖清单(如 go.mod、package.json、requirements.txt)比源码稳定得多,应优先 COPY 并安装。
- Go 项目:COPY go.mod go.sum ./ → RUN go mod download → COPY . .
- Node.js:COPY package*.json ./ → RUN npm ci --only=production → COPY . .
- Python:COPY requirements.txt . → RUN pip install --no-cache-dir -r requirements.txt → COPY . .
减少中间层干扰,提升复用率
每层都保留上层全部文件,冗余内容会膨胀体积、降低缓存命中率。
- 用 COPY 替代 ADD,除非需要自动解压 tar 包;ADD 有隐式行为,容易引入不可控变化
- 敏感操作(如创建用户、设置权限)尽量合并到同一 RUN 中,避免多层留下临时状态
- 显式使用 WORKDIR,避免路径叠加导致 COPY 行为不可预期
- 配好 .dockerignore,排除日志、node_modules、.git 等无关文件,防止误触发缓存失效
多阶段构建分离编译与运行环境
编译环境和运行环境彻底分开,既能瘦身镜像,又能天然隔离构建期变化对运行层缓存的影响。
- 第一阶段用 golang:1.22 构建二进制,第二阶段用 alpine:3.20 仅 COPY 可执行文件
- 构建阶段的依赖、源码、缓存全部不进入最终镜像,不影响运行层缓存逻辑
- CI/CD 中可配合 --cache-from 加载上一次构建缓存,进一步提速


















