Bumping package.json版本而不会使docker缓存失效
我正在使用一个非常标准的Dockerfile来容纳Node.js应用程序:
# Simplified version
FROM node:alpine
# Copy package.json first for docker build's layer caching
COPY package.json package-lock.json foo/
RUN npm install
COPY src/ foo/
RUN npm run build
将我的COPY
分成两部分是有利的,因为它允许Docker缓存(长)npm install
步骤。
然而,最近,我开始使用semver撞击我的package.json
版本。这具有使npm install
步骤的Docker缓存无效的副作用,显着延长了我的构建时间。
是否有我可以使用的替代缓存策略,以便npm install
仅在我的依赖项更改时运行?
我花了一些时间思考这个问题。从根本上说,我作弊是因为package.json
文件实际上已经改变了,这意味着任何绕过缓存失效的技术都会使构建不可重复。
但是,出于我的目的,我更关心构建时间而不是严格的缓存正确性。这是我想出的:
集结artifacts.js
/*
Used to keep docker cache fresh despite package.json version bumps.
In this script
- copy package.json to package-artifact.json
- zero package.json version
In Docker
- copy package.json
- run npm install normal
- copy package-artifact.json to package.json (undo-build-artifacts.js accomplishes this with a conditional check that package-artifact exists)
*/
const fs = require('fs');
const package = fs.readFileSync('package.json', 'utf8');
fs.writeFileSync('package-artifact.json', package);
const modifiedPackage = { ...JSON.parse(package), version: '0.0.0' };
fs.writeFileSync('package.json', JSON.stringify(modifiedPackage));
const packageLock = fs.readFileSync('package-lock.json', 'utf8');
fs.writeFileSync('package-lock-artifact.json', packageLock);
const modifiedPackageLock = { ...JSON.parse(packageLock), version: '0.0.0' };
fs.writeFileSync('package-lock.json', JSON.stringify(modifiedPackageLock));
撤消 - 建造 - artifacts.js
const fs = require('fs');
const hasBuildArtifacts = fs.existsSync('package-artifact.json');
if (hasBuildArtifacts) {
const package = fs.readFileSync('package-artifact.json', 'utf8');
const packageLock = fs.readFileSync('package-lock-artifact.json', 'utf8');
fs.writeFileSync('package.json', package);
fs.writeFileSync('package-lock.json', packageLock);
fs.unlinkSync('package-artifact.json');
fs.unlinkSync('package-lock-artifact.json');
}
这两个文件用于重新定位package.json
和package-lock.json
,将其替换为具有清零版本的工件。这些工件将在docker构建中使用,并将在npm install
完成时替换为原始版本。
我在Travis CI build-artifacts.js
中运行before_script
,在Dockerfile本身运行undo-build-artifacts.js
(在我npm install
之后)。 undo-build-artifacts.js
包含对构建工件的检查,这意味着如果build-artifacts.js
没有运行,Docker容器仍然可以构建。这使得容器在我的书中足够便携。 :)