为啥在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败?

Posted

技术标签:

【中文标题】为啥在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败?【英文标题】:Why does `package-lock.json` causes a failure in a docker container build when `npm install`?为什么在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败? 【发布时间】:2020-12-29 07:23:56 【问题描述】:

网上有很多人以不同的方式问同样的问题,但没有明确的答案。任何人都可以理解为什么docker build 在应用程序中存在package-lock.json 文件时会失败,但在不存在时会成功运行吗?貌似和npm有关,但不清楚。

Everybody 说删除package-lock.json,但它的存在是有原因的。

注意: npm install 在我的本地机器上工作正常,只是在 docker 容器中失败。

如果我有这个 Dockerfile:

# First Stage: Builder
FROM node:13.12.0-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

然后运行:

docker build -t container-tag ./

我明白了:

npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/eventsource-c2615740/example/index.html'
npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/eventsource-c2615740/example/sse-client.js'
npm WARN tar ENOENT: no such file or directory, open '/app/node_modules/.staging/react-router-a14663ae/README.md'

但是这个 Dockerfile 会运行成功:

# First Stage: Builder
FROM node:13.12.0-alpine AS build
WORKDIR /app
COPY package.json ./       #<-------- note that there is no start here
RUN npm install
COPY . .
RUN npm run build

【问题讨论】:

我不确定它是否回答了你的问题,这就是为什么它是一个评论,但我专注于这一部分:“注意:npm install 在我的本地机器上工作正常,只是在 docker 容器中失败” .如果您使用npm install,则不确定是否具有相同版本的依赖项这就是 package-lock.json 的用途,为了拥有可重现的环境,由于版本控制而出现意外问题,您应该改用 npm ci .如果这不能解决您的问题,您需要继续调查,但 IMO 这应该是第一步。希望对您有所帮助。 有道理 - 我不知道 npm ci,将了解更多信息 - 非常感谢 【参考方案1】:

根据您的问题:

注意:npm install 在我的本地机器上工作正常,只是在 docker 容器中失败

如果您使用npm install,则不确定是否具有相同版本的依赖项。

为了拥有一个可重现的环境,并且不会因为不同版本的依赖关系而出现意外问题,您宁愿使用npm ci

这个命令类似于npm-install,除了它是用来 在自动化环境中,例如测试平台,连续 集成和部署 - 或您想要进行的任何情况 确保您正在对依赖项进行全新安装。有可能 通过跳过某些内容,明显快于常规 npm 安装 面向用户的功能。它也比常规安装更严格, 这可以帮助捕获由 大多数 npm 用户的增量安装本地环境。

简而言之,使用 npm install 和 npm ci 的主要区别 是:

项目必须有一个现有的 package-lock.jsonnpm-shrinkwrap.json。 如果包锁中的依赖项与 package.json 中的依赖项不匹配,npm ci 将退出并报错,而不是更新包锁。 npm ci 一次只能安装整个项目:无法使用此命令添加单个依赖项。 如果 node_modules 已经存在,它将在 npm ci 开始安装之前自动删除。 它永远不会写入 package.json 或任何包锁:安装基本上是冻结的。

F*** Gander's article 进一步说明了 npm installnpm ci 工具,并就何时使用每个工具提供了建议。下表来自该来源:

  cases                                | npm install | npm ci
 --------------------------------------|-------------|-------------
  needs package.json                   | no          | yes
  needs package-lock.json              | no          | yes
  installs from package.json           | yes         | no
  installs from package-lock.json      | no          | yes
  compares both                        | no          | yes
  updates loose package versions       | yes         | no
  updates loose dependencies           | yes         | no
  writes to package.json               | yes         | no
  writes to package-lock.json          | yes         | no
  deletes node_modules before install  | no          | yes
  used for installing separate package | yes         | no
  should be used on build systems / CI | no          | yes
  can be used for development          | yes         | yes
  reproducible installs                | no          | yes

这就是 package-lock.json 存在的原因,可用于npm ci 等工具。

拥有可重现的环境后,如果这不能解决您的问题,您需要继续调查,但 IMO 应该是第一步。

【讨论】:

【参考方案2】:

您的本地构建成功但 Docker 构建失败的一些原因可能是(按可能性顺序)

您已经用主机中的node_modules 文件夹覆盖了您的node_modules 文件夹的Alpine Linux 版本,因为您没有.dockerignore node_modules 并且在node_modules 存在时发出了复制/添加命令在主机上的.

但是,我无法解释为什么从 COPY 中省略 package-lock.json 会使构建工作。所以问题也可能涉及:

当您生成 package-lock.json 时,您 npm install-ed 在与 Dockerfile 中指定的不同版本的节点下本地编辑 当您生成 package-lock.json 时,您在与 Alpine Linux 不同的操作系统下本地构建 当您生成 package-lock.json 时,您 npm install-ed 在与 Docker 容器不同版本的 npm 下本地编辑,它可能对 lockfile 关系的处理方式不同

所有这些操作都可能会导致生成package-lock.json,这可能会导致容器中的npm install(更有可能导致npm ci)失败。我不确定为什么这些会导致您发布的特定错误。

如果这些原因可能是问题所在,那么问题的正确解决方案肯定是进行所有 npm 操作(包括您对 package.jsonpackage-lock.json 的生成和操作)内部相同您打算在其中运送代码的 docker 容器的规范,以及 work out a way to commit the results to source control from there。这可能会因诸如在您推送源代码更改的同一环境中需要构建 node_modules 的多个问题而变得复杂(例如,其结果需要推送到容器中的构建步骤,或需要安装的 git 挂钩) .我还没有看到这个问题的完美解决方案

【讨论】:

以上是关于为啥在 `npm install` 时`package-lock.json` 会导致 docker 容器构建失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 npm install 在 git bash 上不起作用

节点。 npm install 后找不到 gulp

为啥`npm install -g` 不适用于 web3?

为啥我必须运行两次“npm install”才能成功安装我的包

为啥“npm install”会修改 package-lock.json?那为啥要把它提交给git呢?

Centos:$ npm install -g vue-cli module.js:549 为啥任何的npm install均报此错,在window上的是正常