当版本碰撞React应用程序时,如何使用docker build cache?
当package.json或package-lock.json中的内容发生更改时,Docker不会使用构建缓存,即使这只是文件中的版本号,也不会更改依赖项 我如何才能做到让docker每次都使用旧的构建缓存并跳过npm安装(npm ci)? 我知道docker会查看文件的修改日期。但是package.json根本没有改变,只更改了版本号 下面是我的Dockerfile当版本碰撞React应用程序时,如何使用docker build cache?,docker,npm,caching,build,package.json,Docker,Npm,Caching,Build,Package.json,当package.json或package-lock.json中的内容发生更改时,Docker不会使用构建缓存,即使这只是文件中的版本号,也不会更改依赖项 我如何才能做到让docker每次都使用旧的构建缓存并跳过npm安装(npm ci)? 我知道docker会查看文件的修改日期。但是package.json根本没有改变,只更改了版本号 下面是我的Dockerfile FROM node:10 as builder ARG REACT_APP_BUILD_NUMBER=X ENV REACT_
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缓存装载 使用实验标志部分缓解此问题。在映像构建过程中,它支持可重用的缓存装载 这里的一个重要警告是,对Docker BuildKit的支持在CI/开发环境之间可能会有很大差异。检查文档和构建环境,以确保它具有适当的支持(否则,它将出错)。以下是一些要求(但不一定是详尽的清单):
- Docker守护程序需要支持BuildKit(需要Docker 18.09+)
- Docker BuildKit需要通过
Docker\u 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\u modules
仍然是不可忽略的节点单元模块
将不包含在最终构建中,并且仅在构建期间可用(但是,将存在一个延迟的/usr/src/app/.npm
目录).npm
- 如果需要,可以清除生成缓存,请参阅
- 不建议缓存
。删除节点\u模块
中的依赖项可能无法正确传播。如果尝试,您的milage可能会有所不同package.json
解决方案二:在复制
package.json之前安装依赖项
在主机上,脚本仅从package.json
中提取依赖项
和devDependencies
标记,并将这些标记复制到新文件中,例如package dependencies.json
例如,包依赖项.json
:
{
“依赖项”:{
“反应”:“^16.13.1”
},
“依赖性”:{
“吞咽”:“^4.0.2”,
}
}
在Dockerfile
中,复制包依赖项.json
和包锁定.json
并安装依赖项。然后,复制原始的package.json
。除非对package lock.json
或package.json
的依赖项发生更改
/devdependency
标记,否则将缓存这些层并从以前的版本中重新使用,这意味着对包的细微更改。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
将出现在层历史记录中。虽然该文件的大小可以忽略不计,但它仍然是“浪费的空间”,因为在最终图像中不需要它
- 需要一个快速脚本来生成
包依赖项.json
。根据构建环境的不同,这可能会使实现变得烦人。以下是使用cli实用程序的示例:
解决方案三:上述所有问题
解决方案I将启用在本地缓存npm依赖项,以便更快地获取依赖项。如果依赖项或开发依赖项被更新,解决方案II将只触发npm ci
/npm install
。这些解决方案可以一起使用以进一步加快构建时间。谢谢,好的,当我将依赖项提取到一个单独的文件中时,假设主机系统将创建此文件,但它将创建为一个新文件,docker是否检查要缓存的文件内容或文件创建日期?在下一个npm安装阶段,它将立即缓存。嗯,好的,让我试试这个。@网站管理员,它应该检查相关文件的内容,以获得层缓存,而不是文件创建或修改日期。我想我发现了我的问题,因为我在docker映像的最顶部包含了REACT_APP_BUILD_编号,当然,每个版本都不同:)
cat package.json | jq -S '. | with_entries(select (.key as $k | ["dependencies", "devDependencies"] | index($k)))' > package-dependencies.json