当版本碰撞React应用程序时,如何使用docker build cache?

当版本碰撞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_

当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_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模块
    。删除
    package.json
    中的依赖项可能无法正确传播。如果尝试,您的milage可能会有所不同

解决方案二:在复制
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