在编写 Dockerfile 时如何有效利用缓存,又如何强制不使用缓存?
在 Docker 构建过程中,合理利用缓存可以极大地缩短构建时间(从几分钟缩短到几秒钟)。但有时为了确保获取最新的依赖包或代码,我们又需要强制禁用缓存。
以下是关于如何有效利用缓存以及如何强制不使用缓存的详细指南:
一、如何有效利用 Docker 构建缓存
Docker 的缓存机制是基于层(Layer)的。在构建时,Docker 会逐行检查 Dockerfile 中的指令,并对比历史构建。如果指令及相关文件没有变化,Docker 就会直接使用缓存(显示为 Using cache)。
要最大化利用缓存,请遵循以下核心原则:
1. 遵守“将不常变动的步骤放前面,经常变动的放后面”原则
Docker 缓存是链式的。一旦某一行代码的缓存失效,它后面的所有步骤的缓存都会失效。
- 不好的顺序:先复制源码,再安装依赖。
- 好的顺序:先安装依赖,再复制源码。
2. 核心技巧:分离“依赖安装”和“代码复制”
这是最经典、最有效的优化手段。以 Node.js 和 Python 项目为例:
Node.js 示例:
FROM node:18-alpine
WORKDIR /app
# 1. 只复制依赖描述文件(极少变动)
COPY package.json package-lock.json ./
# 2. 安装依赖(只有 package.json 变动时才会重新执行,否则走缓存)
RUN npm install
# 3. 复制其余源码(经常变动,放在最后)
COPY . .
CMD ["node", "server.js"]
Python 示例:
FROM python:3.9-slim
WORKDIR /app
# 1. 先复制 requirements.txt
COPY requirements.txt .
# 2. 安装依赖(只要 requirements.txt 没变,就用缓存)
RUN pip install -r requirements.txt
# 3. 复制源码
COPY . .
3. 合并 RUN 指令以减少层数并清理缓存
每个 RUN 都会创建新的一层。为了减少镜像体积并确保缓存的正确性,应该将相关的操作合并。
- 注意:在使用
apt-get时,务必将apt-get update和apt-get install写在同一个RUN指令中。如果分开写,apt-get update的缓存可能会导致你以后安装软件时无法获取最新的包。
# 正确的做法:合并并清理
RUN apt-get update && apt-get install -y \
curl \
git \
&& rm -rf /var/lib/apt/lists/*
4. 使用 .dockerignore 文件
如果不用 .dockerignore,任何本地文件的修改(比如日志、临时文件、.git 目录)在执行 COPY . . 时都会导致缓存失效。
在项目根目录创建 .dockerignore:
.git
node_modules
*.log
dist
.env
二、如何强制不使用缓存
有时候,你可能更新了外部源(例如 GitHub 上的代码、Ubuntu 的软件源),但 Dockerfile 里的指令没变,Docker 会错误地使用缓存。此时你需要强制禁用缓存。
方法 1:在构建命令中加入 --no-cache(最常用、最干净)
在执行 docker build 时,加上 --no-cache 参数。这会告诉 Docker 忽略所有已有缓存,重新执行每一步。
docker build --no-cache -t my-image:latest .
方法 2:使用 --build-arg 引入“缓存破除器”(Cache Buster)
如果你只想从某一步骤开始禁用缓存,而不是完全从头开始(因为从头安装基础依赖很慢),可以使用构建参数(Build Args)。
在 Dockerfile 中:
FROM node:18-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install # 这一步依然想用缓存
# 定义一个构建参数
ARG CACHEBUST=1
# 从这里开始,只要传入的 CACHEBUST 值不同,缓存就会失效
# 比如拉取最新的 Git 代码
RUN git clone https://github.com/user/repo.git
构建时:
每次想要强制更新后面步骤时,只需传入一个不同的值(比如当前时间戳):
docker build --build-arg CACHEBUST=$(date +%s) -t my-image .
方法 3:利用 ADD 指令引入远程 URL
Docker 的 ADD 指令如果指向一个远程 URL,它会检查该 URL 对应文件的内容是否改变。如果改变了,ADD 及其后续的缓存都会失效。这可以用来作为特定步骤的缓存开关。
总结思维导图
| 目标 | 常用手段 |
|---|---|
| 高效利用缓存 | 1. 依赖安装在前,源码复制在后 2. 合并 RUN apt-get update && apt-get install3. 使用 .dockerignore 排除无关文件 |
| 强制禁用缓存 | 1. 全局禁用:docker build --no-cache ...2. 局部禁用:使用 ARG CACHEBUST=$(date +%s) |