当 package.json 或 package-lock.json 中的某些内容发生更改时,Docker 不会使用构建缓存,即使这只是文件中的版本号,也不会更改依赖项。
我怎样才能实现它,以便 docker 每次都使用旧的构建缓存并跳过 npm install (npm ci)? 我知道 docker 会查看文件的修改日期。但 package.json 根本没有改变,只是版本号改变了。
下面是我的 Dockerfile
FROM node:10 as builder
ARG REACT_APP_BUILD_NUMBER=X
ENV REACT_APP_BUILD_NUMBER="${REACT_APP_BUILD_NUMBER}"
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY .npmrc ./
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine
COPY nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /usr/src/app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
以下是一些有助于缓解此问题的解决方案。每种方法都需要权衡,但它们不一定是相互排斥的 - 它们可以混合在一起以获得更好的整体构建性能。
Docker BuildKit 使用实验性
RUN --mount=type=cache
标志可以部分缓解此问题。它支持在映像构建过程中可重用的缓存挂载。
这里需要注意的是,不同 CI/开发环境对 Docker BuildKit 的支持可能存在很大差异。检查文档和构建环境以确保它有适当的支持(否则,它将出错)。以下是一些要求(但不一定是详尽的列表):
DOCKER_BUILDKIT=1
显式启用,或者默认从守护进程/cli 配置启用。Dockerfile
开头添加注释以启用实验支持:# syntax=docker/dockerfile:experimental
这里是一个利用此功能的示例
Dockerfile
,将 npm 依赖项本地缓存到 /usr/src/app/.npm
,以便在后续构建中重用:
# syntax=docker/dockerfile:experimental
FROM node
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
COPY package.json package-lock.json /usr/src/app
RUN --mount=type=cache,target=/usr/src/app/.npm \
npm set cache /usr/src/app/.npm && \
npm ci
备注:
npm
仍需要将它们安装到 node_modules
目录中。对中型项目的测试表明,这确实减少了一些构建时间,但构建node_modules
仍然是不可忽略的。/usr/src/app/.npm
将不会包含在最终版本中,并且仅在构建期间可用(但是,挥之不去的.npm
目录will存在)。node_modules
。删除package.json
中的依赖关系可能无法正确传播。如果尝试的话,您的里程可能会有所不同。package.json
在主机上,脚本仅从
dependencies
中提取 devDependencies
和 package.json
标签,并将这些标签复制到新文件中,例如 package-dependencies.json
。
例如
package-dependencies.json
:
{
"dependencies": {
"react": "^16.13.1"
},
"devDependencies": {
"gulp": "^4.0.2",
}
}
在
Dockerfile
、COPY
、package-dependencies.json
和 package-lock.json
中并安装依赖项。然后,复制原来的package.json
。除非 package-lock.json
或 package.json
的 dependencies
/devDependencies
标签发生更改,否则这些层将被缓存并从之前的构建中重用,这意味着对 package.json
的微小更改将不需要运行 npm ci
/npm install
.
这是一个例子:
FROM node
RUN mkdir -p /usr/src/app
WORKDIR /usr/src/app
# copy dependency list and locked dependencies
COPY package-dependencies.json package-lock.json /usr/src/app/
# install dependencies
RUN npm ci
# copy over the full package configuration
COPY package.json /usr/src/app/
# ...
RUN npm run build
# ...
备注:
npm ci
。package-dependencies.json
将出现在图层历史记录中。虽然此文件的大小可以忽略不计/无关紧要,但它仍然是“浪费的空间”,因为最终图像中不需要它。package-dependencies.json
。根据构建环境的不同,这可能实施起来很烦人。以下是使用 cli 实用程序 jq
的示例:
cat package.json | jq -S '. | with_entries(select (.key as $k | ["dependencies", "devDependencies"] | index($k)))' > package-dependencies.json
解决方案我将在本地启用 npm 依赖项缓存,以加快依赖项获取速度。仅当依赖项或开发依赖项更新时,解决方案 II 才会触发
npm ci
/npm install
。这些解决方案可以一起使用,以进一步加快构建时间。