如何在Docker中安装nvm?

182
我正在构建一个新的Docker映像,希望安装NVM以便管理nodejs。
阅读有关安装NVM的文档时,他们提到您需要在.bashrc文件中进行源设置才能开始使用NVM。
我尝试在Dockerfile中设置这个,但是到目前为止构建失败并显示以下错误信息:“bash:nvm:找不到命令”。
以下是我Dockerfile中相关的行:
ADD files/nvm_install.sh /root/
RUN chmod a+x  /root/nvm_install.sh
RUN bash -c "/root/nvm_install.sh"
RUN bash -l -c "source /root/.bashrc"
RUN cd /root
RUN bash -l -c "nvm install 0.10.31"

以下是尝试构建的输出结果:

docker build -t nginx_dock .

Step 0 : FROM ubuntu
---> 826544226fdc
Step 1 : MAINTAINER dficociello
---> Using cache
---> da3bc340fbb3
Step 2 : RUN apt-get update
---> Using cache
---> 6b6b611feb4f
Step 3 : RUN apt-get install nginx curl -y
---> Using cache
---> 159eb0b16d23
Step 4 : RUN touch /root/.bashrc
---> Using cache
---> 5e9e8216191b
Step 5 : ADD files/nginx.conf /etc/nginx/
---> Using cache
---> c4a4a11296a2
Step 6 : ADD files/nvm_install.sh /root/
---> Using cache
---> b37cba2a18ca
Step 7 : RUN chmod a+x  /root/nvm_install.sh
---> Using cache
---> bb13e2a2893d
Step 8 : RUN bash -c "/root/nvm_install.sh"
---> Using cache
---> 149b49a8fc71
Step 9 : RUN bash -l -c "source /root/.bashrc"
---> Running in 75f353ed0d53
---> 0eae8eae7874
Removing intermediate container 75f353ed0d53
Step 10 : RUN cd /root
---> Running in feacbd998dd0
---> 284293ef46b0
Removing intermediate container feacbd998dd0
Step 11 : RUN bash -l -c "nvm install 0.10.31"
---> Running in 388514d11067
bash: nvm: command not found
2014/09/17 13:15:11 The command [/bin/sh -c bash -l -c "nvm install 0.10.31"] returned a non-zero         code: 127

我对Docker还比较陌生,可能会忽略一些编写Dockerfile的基础知识,但是到目前为止,我所阅读的所有资料都没有给我展示一个好的解决方案。


16
不是重复内容,因为这是针对在Docker内安装而不是标准安装的特定问题。 - David Ficociello
1
由于您只安装了一个版本的Node,因此似乎没有必要安装nvm。 Docker [node repository](https://hub.docker.com/_/node/)提供的Dockerfiles可用作安装node的参考。 - mikwat
2
@mikwat 我同意你的想法,但有一些有效的用例。例如,我正在docker镜像中运行AWS CDK测试,并且我希望测试镜像中使用的节点版本能够根据我在本地repo中拥有的.nvmrc动态更新。这样就不太可能出现我在本地更新了节点版本,但忘记在docker镜像中更新它的情况了。 - medley56
nvm 对你的使用情况绝对有意义 @medley56 - mikwat
26个回答

173

每次运行RUN bash...都会在一个单独的进程中运行,环境中设置的任何内容都不会保留。这是我安装nvm的方法:

# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

# Set debconf to run non-interactively
RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections

# Install base dependencies
RUN apt-get update && apt-get install -y -q --no-install-recommends \
        apt-transport-https \
        build-essential \
        ca-certificates \
        curl \
        git \
        libssl-dev \
        wget \
    && rm -rf /var/lib/apt/lists/*

ENV NVM_DIR /usr/local/nvm # or ~/.nvm , depending
ENV NODE_VERSION 0.10.33

# Install nvm with node and npm
RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.20.0/install.sh | bash \
    && . $NVM_DIR/nvm.sh \
    && nvm install $NODE_VERSION \
    && nvm alias default $NODE_VERSION \
    && nvm use default

ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH      $NVM_DIR/v$NODE_VERSION/bin:$PATH

要将速度加快一倍,只需将“v0.20.0”更改为“v0.24.1”。 - itsnikolay
11
使用 nvm 0.31.0 和 node v4.2.3,路径为 /usr/local/nvm/versions/node/v4.2.3/bin - cwhsu
7
这并不解释为什么提问者安装的 nvm 不起作用,而其他答案却有效。这与运行在单独进程中的 shell 无关。原因是该问题试图使用 source bash.rc 命令来加载 nvm.sh 文件,该文件将 nvm 命令加载到 bash 中,但是当以非交互方式运行时,bash.rc 会很早就退出,因此 nvm 命令不被加载。所有成功的答案都是直接通过 source nvm.sh 命令来加载 nvm.sh 文件,而不是通过 bash.rc 来加载。这是使其正常工作的关键。 - tobuslieven
5
不必将 sh 替换为 bash,只需运行. $NVM_DIR/nvm.sh即可避免使用 source 二进制文件。 - Razvan Grigore
6
这个很接近,但路径需要稍作调整,应该是:ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH - iepathos
显示剩余4条评论

85

更新 2020年2月20日:如果您使用的是基于debian的映像,则此解决方案有效。如果您使用的是ubuntu,请参见此答案

这是我找到的安装nvm最干净的方法:

SHELL ["/bin/bash", "--login", "-c"]

RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
RUN nvm install 10.15.3

说明

  • 第一行将Dockerfile的默认shell设置为bash登录shell。注意:这意味着每个后续的RUNCMDENTRYPOINT都将在当前用户(通常是root)下运行,并且如果以shell形式运行,则会源自~/.bashrc文件。

  • 第二行安装了带有bash的nvm。当使用bash运行脚本时,它会附加到~/.bashrc文件。

  • 第三行安装了特定版本的nodejs并使用它。因为它们是通过bash登录shell运行的(参见第1行),所以nvmnpmnode命令都可用。


2
有趣的是这对你起作用了。我尝试了类似的东西,在构建过程中一切看起来都很好,但当我去运行生成的镜像时,NPM找不到。明确设置NVM_DIR(如其他答案中所示)为我解决了这个问题。 - esmail
2
@esmail 这很奇怪,因为第一个 RUN 命令在 ~/.bashrc 中设置了 NVM_DIR - Dominic Roy-Stang
2
@DominicRoy-Stang,说得好。我正在使用的镜像使用了sh,因此忽略了.bashrc。另外,您确定在执行RUN命令之前确实会加载.bashrc吗?在我对官方bash镜像进行的简短测试中,似乎并不是这样。 - esmail
2
@esmail 这就是第一行(SHELL指令)的作用。它使连续的RUN命令使用登录shell,该shell会源化.bashrc文件。注意:它只在shell模式下运行命令时有效,例如RUN nvm --version。如果在exec模式下运行命令,例如RUN ["nvm", "--version"],则无效。我已更新提供的shell表单链接,希望这样更明显。 - Dominic Roy-Stang

42
为了帮助那些正在寻找在Ubuntu上安装Node.js和NVM的方法的人,我创建了以下的dockerfile。我使用的是最新版本的Docker、Ubuntu、Node.js,并且NVM正常工作($PATH被修复)。我将其用于生产环境中。
$ docker info \
Server Version: 1.9.1
Kernel Version: 4.1.13-boot2docker
Operating System: Boot2Docker 1.9.1 (TCL 6.4.1); master : cef800b - Fri Nov 20 19:33:59 UTC 2015

Node.js Version: stable 4.2.4 LTS
Ubuntu Version: 14.04.3


dockerfile:

FROM ubuntu:14.04.3

# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

# make sure apt is up to date
RUN apt-get update --fix-missing
RUN apt-get install -y curl
RUN apt-get install -y build-essential libssl-dev

ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION 4.2.4

# Install nvm with node and npm
RUN curl https://raw.githubusercontent.com/creationix/nvm/v0.30.1/install.sh | bash \
    && source $NVM_DIR/nvm.sh \
    && nvm install $NODE_VERSION \
    && nvm alias default $NODE_VERSION \
    && nvm use default

ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH      $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH

RUN mkdir /usr/app
RUN mkdir /usr/app/log

WORKDIR /usr/app

# log dir
VOLUME /usr/app/log

# Bundle app source
COPY . /usr/app
# Install app dependencies
RUN npm install

EXPOSE  3000
CMD ["node", "server.js"]

1
NODE_PATH不应该是ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules。 - Sentient
你好 @Sentient!我正在生产环境(ubuntu)和本地开发(OSX)中运行这个docker,两者都正常工作,没有错误。你可能在运行过时的NVM吗? - danilodeveloper
我安装build-essential和libssl-dev时,是否有必要使用SUDO?我并不是一个经验丰富的DevOps。 - a.barbieri
1
关键是 source $NVM_DIR/nvm.sh && nvm install $NODE_VERSION - Val Kornea

42

Nvm路径自被接受的答案以来已经发生了变化,因此如果您想使用更高版本的nvm,您需要进行一些更改。此外,没有必要重新映射sh使其正常工作:

ENV NVM_DIR /usr/local/nvm
RUN mkdir -p $NVM_DIR
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.1/install.sh | bash
ENV NODE_VERSION v7.9.0
RUN /bin/bash -c "source $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use --delete-prefix $NODE_VERSION"

ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/lib/node_modules
ENV PATH      $NVM_DIR/versions/node/$NODE_VERSION/bin:$PATH

不确定您是否需要在nvm use命令中使用--delete-prefix选项,但我需要使用,不过这可能与我的基础映像有关。


3
救命稻草!要是我三个小时前就看到你的回复就好了。 - Adrian Marinica
3
你可能想要添加 RUN mkdir -p $NVM_DIR。似乎较新版本的 nvm 会检查该目录是否存在。 - yesennes
1
这是我在2022年尝试在Amazon Linux 2中安装NVM时唯一有效的解决方案。 - Raj
1
可以确认:在苦苦挣扎数小时后,这个方法于2022年11月对我有效。谢谢!专业提示...总是向下滚动查看其他答案 :) - RobTheRobot16
2
2023年三月到了,只有工作的解决方案才是王道! - myriacl
显示剩余3条评论

39
花了我一两个小时来找出最干净的方法。-登录似乎不执行 .bashrc,所以你必须提供 -i 以交互模式启动它。这会导致 Docker 对你发出警告,所以我仅在安装时以此方式启动,然后重置为我的标准 shell。
# Installing Node
SHELL ["/bin/bash", "--login", "-i", "-c"]
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.2/install.sh | bash
RUN source /root/.bashrc && nvm install 12.14.1
SHELL ["/bin/bash", "--login", "-c"]

1
你的回答让我意识到我的基于 debian 镜像的代码不能在 ubuntu 镜像上运行(但是你的可以)。我不确定这两者之间的差异是什么原因造成的。有什么想法吗? - Dominic Roy-Stang
我使用Ubuntu 19:10作为基础镜像。我将发布所有相关的Docker指令,以便您了解对我有效的内容。任何我省略的指令要么不相关,要么无法提供。我会用注释表示它们。由于字符限制设置过低,我将在下一个评论中发布它们。 - user2896438
这里有类似的技术:https://gist.github.com/remarkablemark/aacf14c29b3f01d6900d13137b21db3a#gistcomment-3067813,同时也与此相关:https://www.kabisa.nl/tech/nvm-in-docker/,是关于在Docker容器中进行Node版本管理的。 - mhulse

36
这是我的Dockerfile,准备好复制/粘贴,其中我安装了最新的nvm 2022版本和最新的Ubuntu

简化版本

适用于Docker和Linux专家

FROM ubuntu

ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION v16.17.0
RUN mkdir -p /usr/local/nvm && apt-get update && echo "y" | apt-get install curl
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
RUN /bin/bash -c "source $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use --delete-prefix $NODE_VERSION"
ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/bin
ENV PATH $NODE_PATH:$PATH

详细而教学性的版本
FROM ubuntu

# nvm requirements
RUN apt-get update
RUN echo "y" | apt-get install curl
# nvm env vars
RUN mkdir -p /usr/local/nvm
ENV NVM_DIR /usr/local/nvm
# IMPORTANT: set the exact version
ENV NODE_VERSION v16.17.0
RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash
RUN /bin/bash -c "source $NVM_DIR/nvm.sh && nvm install $NODE_VERSION && nvm use --delete-prefix $NODE_VERSION"
# add node and npm to the PATH
ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/bin
ENV PATH $NODE_PATH:$PATH
RUN npm -v
RUN node -v

日志

enter image description here

注意事项


这个 Dockerfile 是有效的。只需要一个更正,版本目录有一个前缀“v”。ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/lib/node_modules ENV PATH $NVM_DIR/versions/node/$NODE_VERSION/bin:$PATH - nashter
有没有办法确保 nvm.sh 在所有后续的命令中仍然被调用? - undefined
分享错误。在ENV NODE_PATH $NVM_DIR/versions/node/$NODE_VERSION/bin之后,nvm已经被源化。 - undefined
1
适用于Ubuntu,截至2023年10月 - undefined
1
这真是让我大跌眼镜,我居然在一个针对asp.net core 7 minimal apis(内置react SPA)的dockerfile中简单地运行npm run build时遇到了这么大的困难——你的答案终于让这个问题得以解决,现在我有了一个包含静态构建文件的wwwroot文件夹。谢谢你,但同时,这也太难了吧!? - undefined
显示剩余6条评论

27

在Dockerfile中,每个RUN都在一个不同的容器中执行。因此,如果您在一个容器中源文件,它的内容将无法在下一个容器中使用。

这就是为什么当您安装一个应用程序并且需要执行多个步骤时,必须在同一个容器中完成的原因。

以您的示例为例:

ADD files/nvm_install.sh /root/
RUN chmod a+x /root/nvm_install.sh && \
  /root/nvm_install.sh && \
  source /root/.bashrc && \
  cd /root && \
  nvm install 0.10.31

好的,非常感谢您的解释。 所以我修改了我的脚本,现在看起来像这样: `FROM ubuntu MAINTAINER dficociello ADD files/nvm_install.sh /root/

安装 nvm

RUN ["/bin/bash", "-c", "rm -f /etc/nginx/nginx.conf && touch /root/.bashrc && apt-get update && apt-get install nginx curl -y && chmod a+x /root/nvm_install.sh && source /root/.bashrc && /root/nvm_install.sh && nvm install 0.10.31"] ADD files/nginx.conf /etc/nginx/ EXPOSE 22但是我遇到了以下错误:/bin/bash: /root/nvm_install.sh: /bin/bash: bad interpreter: Text file busy`
- David Ficociello
这个错误一定与你的代码行 RUN ["/bin/bash", ...] 相关。它不应该被包含在 [...] 中,也不需要指定解释器 /bin/bash -c - Kuhess

17

这是基于最佳答案并适用于2018年的方法:

# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

# Install base dependencies
RUN apt-get update && apt-get install -y -q --no-install-recommends \
        apt-transport-https \
        build-essential \
        ca-certificates \
        curl \
        git \
        libssl-dev \
        wget

ENV NVM_DIR /usr/local/nvm
ENV NODE_VERSION 8.11.3

WORKDIR $NVM_DIR

RUN curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash \
    && . $NVM_DIR/nvm.sh \
    && nvm install $NODE_VERSION \
    && nvm alias default $NODE_VERSION \
    && nvm use default

ENV NODE_PATH $NVM_DIR/versions/node/v$NODE_VERSION/lib/node_modules
ENV PATH      $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
请注意,nvm不是bash命令,它是一个别名。如果您依赖于$PATH,这可能会让您出现问题。

14

这是我的工作版本

FROM ubuntu:14.04

# Declare constants
ENV NVM_VERSION v0.29.0
ENV NODE_VERSION v5.0.0

# Replace shell with bash so we can source files
RUN rm /bin/sh && ln -s /bin/bash /bin/sh

# Install pre-reqs
RUN apt-get update
RUN apt-get -y install curl build-essential

# Install NVM
RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/${NVM_VERSION}/install.sh | bash

# Install NODE
RUN source ~/.nvm/nvm.sh; \
    nvm install $NODE_VERSION; \
    nvm use --delete-prefix $NODE_VERSION;

参考了 @abdulljibali 和 @shamisis 的回答。


1
获取~/.nvm/nvm.sh文件是我需要的关键。 - Stephane
这是我在 Ubuntu 16.04.2 容器中唯一有效的解决方案。 - drohm
非常完美!非常感谢您,先生! - Pedro Acácio
必须在安装链接中使用字母“v”(表示版本)来预置${NVM_VERSION} - Umar A.

10
根据@Kuhess回答中的建议,我在我的Dockerfile中用以下代码替换了源命令。
RUN cat ~/.nvm/nvm.sh >> installnode.sh
RUN echo "nvm install 0.10.35" >> installnode.sh
RUN sh installnode.sh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接