docker image 上的 npm global install 没有访问权限错误
Posted
技术标签:
【中文标题】docker image 上的 npm global install 没有访问权限错误【英文标题】:No access permission error with npm global install on docker image 【发布时间】:2017-11-21 20:07:25 【问题描述】:我正在尝试使用 firebase-tools 和 angular-cli 的全局安装构建一个 docker 映像。 我正在为两个版本的节点构建相同的图像:6.x(LTS 硼)和 v8.x(最新的 alpine)。在本地,两个映像都构建得很好,但是当我尝试在 docker hub 中构建时,只有 v6.x 构建成功。在 v8.x 中,它被困在 未定义和无人用户的访问权限中。我已经在使用 root 用户(USER root),因为没有此设置(或使用 USER 节点),两个图像都无法构建。
这是我的 Dockerfile:
FROM node:latest
USER root
RUN npm install --quiet --no-progress -g @angular/cli@latest firebase-tools
RUN npm cache clean --force
这是输出:
Step 4/5 : RUN npm install --quiet --no-progress -g @angular/cli@latest firebase-tools
---> Running in fce3da11b04e
npm WARN deprecated node-uuid@1.4.8: Use uuid module instead
/usr/local/bin/firebase -> /usr/local/lib/node_modules/firebase-tools/bin/firebase
/usr/local/bin/ng -> /usr/local/lib/node_modules/@angular/cli/bin/ng
> node-sass@4.5.3 install /usr/local/lib/node_modules/@angular/cli/node_modules/node-sass
> node scripts/install.js
Unable to save binary /usr/local/lib/node_modules/@angular/cli/node_modules/node-sass/vendor/linux-x64-57 : Error: EACCES: permission denied, mkdir '/usr/local/lib/node_modules/@angular/cli/node_modules/node-sass/vendor'
at Object.fs.mkdirSync (fs.js:890:18)
at sync (/usr/local/lib/node_modules/@angular/cli/node_modules/mkdirp/index.js:71:13)
at Function.sync (/usr/local/lib/node_modules/@angular/cli/node_modules/mkdirp/index.js:77:24)
at checkAndDownloadBinary (/usr/local/lib/node_modules/@angular/cli/node_modules/node-sass/scripts/install.js:111:11)
at Object.<anonymous> (/usr/local/lib/node_modules/@angular/cli/node_modules/node-sass/scripts/install.js:154:1)
at Module._compile (module.js:569:30)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:503:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
errno: -13,
code: 'EACCES',
syscall: 'mkdir',
path: '/usr/local/lib/node_modules/@angular/cli/node_modules/node-sass/vendor'
> grpc@1.3.8 install /usr/local/lib/node_modules/firebase-tools/node_modules/grpc > node-pre-gyp install --fallback-to-build --library=static_library
node-pre-gyp ERR! Tried to download(undefined): https://storage.googleapis.com/grpc-precompiled-binaries/node/grpc/v1.3.8/node-v57-linux-x64.tar.gz node-pre-gyp ERR! Pre-built binaries not found for grpc@1.3.8 and node@8.1.2 (node-v57 ABI) (falling back to source compile with node-gyp)
gyp WARN EACCES user "undefined" does not have permission to access the dev dir "/root/.node-gyp/8.1.2" gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp"
gyp WARN EACCES user "nobody" does not have permission to access the dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp/8.1.2" gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp"
gyp WARN EACCES user "nobody" does not have permission to access the dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp/8.1.2" gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp"
gyp WARN EACCES user "nobody" does not have permission to access the dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp/8.1.2" gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp"
gyp WARN EACCES user "nobody" does not have permission to access the dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp/8.1.2" gyp WARN EACCES attempting to reinstall using temporary dev dir "/usr/local/lib/node_modules/firebase-tools/node_modules/grpc/.node-gyp"
(infinite loop)
【问题讨论】:
【参考方案1】:我能够通过更改默认的 npm-global 目录来使其正常工作。
这是我现在的 dockerfile:
FROM node:latest
USER node
RUN mkdir /home/node/.npm-global
ENV PATH=/home/node/.npm-global/bin:$PATH
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
RUN npm install --quiet --no-progress -g @angular/cli@latest firebase-tools
RUN npm cache clean --force
【讨论】:
你应该接受你自己的答案。目前接受的答案建议使用root
并获得太多的赞成票。【参考方案2】:
问题在于,虽然 NPM 以 nobody
用户身份运行全局安装的模块脚本,这很有意义,但最近版本的 NPM 开始将节点模块的文件权限设置为 root
。因此,不再允许模块脚本在其模块中创建文件和目录。
请参阅讨论in NPM issue #3849,以获取一些参考资料。
一个在 docker 环境中有意义的简单解决方法是将 NPM 默认全局用户设置回root
,如下所示:
npm -g config set user root
在此之后,您不应再有任何EACCES
错误。
【讨论】:
或者也使用npm -g config set user $USER
对我有用,因为我真的希望我的用户成为默认用户,而不是 root。
@DanieleDellafiore 将全局用户设置为个人用户 ID 没有多大意义。也许您只想使用不带全局 (-g
) 标志的 npm
尝试在全球范围内安装cordova-res
,但安装成功后无法正常工作。谢谢。
完美运行!【参考方案3】:
使用--unsafe-perm
标志:
npm install --quiet --no-progress --unsafe-perm -g @angular/cli@latest firebase-tools
我认为这仍然比将npm
用户永久设置为root 更好。 --unsafe-perm
只能用于引起问题的软件包
【讨论】:
【参考方案4】:我没有强迫 NPM 将包安装到容器中,而是通过映射/引用缺少模块的主机文件夹来绕过这个问题 这也可以防止将来当我用最新版本替换 docker 映像时感到头疼,我不必重复这些阶段来在容器内重新安装缺少的模块:
我采取的步骤:
在主机环境中创建一个空文件夹(将用作节点 js 模块的目标)。称之为 node_modules
在启动运行 docker 容器时使用 --volume 和 --env 开关
-- 传递的卷将新的主机文件夹(从步骤 1 开始)映射到 docker 内可访问的文件夹
--env 定义/设置环境变量 NPM_CONFIG_PREFIX 从 docker 内部到我们在步骤 1 中创建的 /node_modules 文件夹
使用 :
访问容器sudo docker exec -i -t sh
然后转到 local /node_modules 文件夹正上方的文件夹(这不是我们映射到环境变量的文件夹,而是 docker 映像附带的预先存在的文件夹)
然后运行命令:
> npm install -g <mdule-name>
例子
> npm install -g request
这会将模块安装在我们创建的主机文件夹中。这个模块也可以从 docker 和 host 访问。
【讨论】:
@kaiser 谢谢,只要人们仍然可以看到和使用这些信息......这才是最重要的【参考方案5】:请请勿将用户设置为root
或使用--unsafe-perm
。
只需使用node
用户,提供当前官方(例如alpine
)图片。
在下方评论Dockerfile
:
FROM node:15.5-alpine
# ? Security: do not use the `root` user.
ENV USER=node
# You can not use `$USER` here, but reference `/home/node`.
ENV PATH="/home/node/.npm-global/bin:$PATH"
# ? The `--global` install dir
ENV NPM_CONFIG_PREFIX="/home/node/.npm-global"
# All subsequent commands are run as the `node` user.
USER "$USER"
# Pre-create the target dir for global install.
RUN mkdir -p "$NPM_CONFIG_PREFIX/lib"
WORKDIR /usr/src/app
COPY package.json package-lock.json ./
# ? Configure NPM, so pkg get installed with correct credentials.
# Avoids `chmod u+x $DIR` and other workarounds.
RUN npm --global config set user "$USER" \
&& npm --global --quiet --no-progress install \
&& npm cache clean --force
@gabriel-araujo 答案的扩展版本。
您可以通过配置此in the .npmrc
file 通过 CLI 标志 (npm --global config set user "$USER"
) 替换 setting the user。将user=node
放在项目根.npmrc
文件中,或者直接从Dockerfile
中设置。
RUN echo "user=node" > "$NPM_CONFIG_PREFIX/etc/.npmrc"
如果您使用docker-compose.yml
,您可以将其添加为environment: - …
变量。
希望能帮助您在某处运行更安全的 NodeJS 容器并提取一些很棒的东西。
【讨论】:
以上是关于docker image 上的 npm global install 没有访问权限错误的主要内容,如果未能解决你的问题,请参考以下文章
npm install 后 Gitlab Shared Runner docker build
vuejs 应用程序不使用 dockerized npm 运行
sbt-native-packager:Alpine Docker Image 上的 Scala 应用程序失败,权限被拒绝