为什么`npm install`时package-lock.json会导致Docker容器构建失败?

问题描述

网上有很多人以不同的方式问这个问题,但没有明确的答案。有人能充分理解为什么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,则不确定是否具有相同版本的依赖项。

要获得可重现的环境,而不会因依赖关系版本不同而出现意外问题,请使用npm ci

此命令与npm-install相似,只不过它是要使用的 在自动化环境(例如测试平台)中,连续 集成和部署–或您要进行的任何情况 确保您正在全新安装依赖项。有可能 通过跳过某些步骤,比常规的npm安装快得多 面向用户的功能。它也比常规安装更严格, 这可以帮助您发现由以下原因引起的错误或不一致之处: 大多数npm用户的增量安装本地环境。

简而言之,使用npm install和npm ci之间的主要区别 是:
  • 项目必须具有现有的 package-lock.json npm-shrinkwrap.json
  • 如果程序包锁中的依赖项与 package.json 中的依赖项不匹配,则 npm ci 会退出并显示错误,而不是更新程序包锁。
  • npm ci 一次只能安装整个项目:不能使用此命令添加单个依赖项。
  • 如果已经存在 node_modules ,它将在 npm ci 开始安装之前自动删除。
  • 它永远不会写入 package.json 或任何软件包锁:安装实际上是冻结的。

Fabian 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应该是第一步。

,

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

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

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

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

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

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