我使用一个非常标准的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
只在依赖关系改变时运行?
8条答案
按热度按时间kiz8lqtg1#
下面是我对这个问题的看法,基于其他的答案,但是比较简短,并且使用了
jq
:停靠文件:
我将
dependencies
和devDependencies
字段提取到一个单独的文件中,然后在下一个构建步骤中,将其从上一个步骤复制为package.json
(COPY --from=deps /tmp/deps.json ./package.json
)。在
RUN npm ci
之后,COPY . .
将用原始的package.json
覆盖已删除的package.json
(您可以通过在COPY . .
命令之后添加RUN cat package.json
来测试它。请注意,npm-scripts commands(如
postinstall
)不会运行,因为在npm ci
期间,它们不存在于文件中,如果npm ci
is running fromroot
且不存在--unsafe-perm
,也不会运行在
COPY . .
之后运行命令或/和(如果需要)通过jq
包含这些命令(更改命令将使缓存图层无效)或添加--unsafe-perm
停靠文件:
gwbalxhn2#
您可以在Dockerfile中添加一个额外的"准备"步骤,创建一个临时的
package.json
,其中的"version"
字段是固定的。这个文件随后在安装依赖项时使用,之后被"真正的"package.json
替换。由于所有这些都发生在Docker构建过程中,因此不会触及您的实际源代码库(因此您可以在构建过程中以及运行Docker脚本时使用环境变量
npm_package_version
,例如标记),并且解决方案是可移植的:如果您认为内联Node脚本有问题(我喜欢它,因为这样可以在Dockerfile中找到整个Docker构建过程),当然可以将其提取到单独的JS文件中:
并将准备步骤更改为:
odopli943#
我花了一些时间思考这个问题,从根本上说,我是在作弊,因为
package.json
文件实际上被更改了,这意味着任何在技术上绕过该高速缓存无效的操作都会使构建不可复制。然而,就我的目的而言,我更关心构建时间而不是严格的缓存正确性。
构建工件.js
撤消生成工件.js
这两个文件用于重新定位
package.json
和package-lock.json
,将它们替换为版本为零的工件。这些工件将在docker构建中使用,并在npm install
完成时替换为原始版本。我在Travis CI
before_script
中运行build-artifacts.js
,并在Docker文件本身中运行undo-build-artifacts.js
(在Inpm install
之后)。undo-build-artifacts.js
包含了对构建工件的检查,这意味着如果build-artifacts.js
没有运行,Docker容器仍然可以构建。ac1kyiln4#
我的做法有点不同,我只是忽略了
package.json
中的版本,并将其设置为1.0.0。相反,我添加了一个文件version.json
,然后使用如下所示的脚本进行部署。如果需要发布到npm,则此方法不起作用,因为版本永远不会更改
version.json
deploy.sh
我通常只是手动更新版本文件,但如果您想要类似
npm version
的工作方式,则可以使用这样的脚本,该脚本使用semvar包。patch.js
pzfprimi5#
基于n3 tn 0 de answer,我将停靠文件更改为
这种方法将避免使用2个不同的Docker映像-更少的下载和存储-并修复/避免package.json中的任何问题
iyfjxgzm6#
另一个选项pnpm现在具有
pnpm fetch
,它只使用锁定文件,因此您可以自由地对package.json
进行其他更改这需要从npm/Yarn切换到使用pnpm
示例来自:https://pnpm.io/cli/fetch
rpppsulh7#
不用jq也可以使用基本的sed来修补版本:
sed正则表达式假定版本值遵循semver方案(例如1. 23. 456)
另一个假设是
"version": "xx.xx.xx
,”字符串在文件的其他地方找不到。模式末尾的“,”可以帮助降低“误报”的概率。当然,出于安全考虑,请在使用package.json
文件之前检查它。pgky5nke8#
步骤:
1.从包json中删除版本
1.安装用于生产的软件包
1.拷贝到生产映像
好处:
实际上: