1FROM ubuntu:21.04
2
3LABEL description="Install Node with nvm"
4
5# Install Node with nvm
6ARG NODE_VERSION=14.17.0
7ENV NPM_CONFIG_USER=root
8ENV NVM_DIR=/root/.nvm
9ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
10
11RUN curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.38.0/install.sh | bash \
12 && . ${NVM_DIR}/nvm.sh \
13 && . ${NVM_DIR}/bash_completion \
14 && echo "\n npm version is: $(npm -v)" \
15 && echo "\n Node version is: $(node -v)"
16
17# Install npm packages and tooling
18# RUN npm i -g --unsafe-perm expo-cli turtle-cli
19# RUN npm i -g netlify-cli appcenter-cli firebase-tools
20
21CMD bash
If you are installing packages globally as the root user, you get the EACCES: permission denied
error. Which is why it is recommended that you install node with a version manager, like nvm
. (Or manually change the default directory for npm
)
root
userWhile installing with nvm
is commonly accepted as the solution to sudo
and root
problems, it still didn’t work for me when installing certain packages globally (e.g. expo-cli
, turtle-cli
). For packages like these, it is usually a postinstall script that check/fix permission since npm
runs postinstall scripts as user nobody
for safety (and not root
).
(nobody
is the default user for npm
while the default user for a docker container is root
). In situations like these, where you want to install packages as root
, you can install a particular package with the --unsafe-perm
flag.
When installing packages globally as root
, you’ll get a bunch of sh: 1: node: Permission denied
errors and will have to use flags like --unsafe-perm=true
and --allow-root
to get rid of them
npm config set user 0
npm config set unsafe-perm true
unsafe-perm
- Set to true to suppress the UID/GID switching when running package scripts. If set explicitly to false, then installing as a non-root user will fail. Default is false
if running as root
, and true
otherwise--unsafe-perm
is always true
unless using root
user
- The UID to set to when running package scripts as root. default is nobody
0
is always the UID of root
userYou can pass these config values as flag by adding a --
to the beginning. If you don’t pass it a value, it becomes true
. --unsafe-perm
is the same as --unsafe-perm true
is the same as --unsafe-perm=true
You can do it on a per install command basis
1npm i -g --unsafe-perm --allow-root expo-cli
Or you can set it for the entire script/container (which is not recommended)
1npm config set user 0
2npm config set unsafe-perm true
3npm i -g expo-cli
While most online answers will include the --allow-root
flag (or npm config set user 0
), i went the ENV NPM_CONFIG_USER=root
route where i set the npm user for the entire Dockerfile
1ENV NPM_CONFIG_USER=root
In the end, i don’t quite see the benefit of installing via nvm since i ended up using these flags anyway and installing packages globally was a troubling experience.
If after installing node with nvm you got /bin/sh: 1: node: not found
on the next step, you need to add node to $PATH
so that it knows where to run node from
1ENV PATH="/root/.nvm/versions/node/v${NODE_VERSION}/bin/:${PATH}"
source ~/.bashrc
did not work as expected inside the docker container. Something to do with Docker using /bin/sh
instead of /bin/bash
. You can change the shell inside the Dockerfile with SHELL ["/bin/bash", "-c"]
or run a particular command in a different shell with RUN ["/bin/bash", "-c", "echo hello all in one string"]
, but neither worked for me when sourcing ~/.bashrc
after having installed nvm
. In the end i looked at the manual installation steps to see what nvm was adding to bashrc (setting NVM_DIR
and then calling a script inside NVM_DIR
called nvm.sh
) and referenced that particular bit directly inside the command (instead of adding it to bashrc). I’m cool with it since i don’t expect to be using nvm
lots of time inside the container. It’s pretty much a one-time thing to install a particular node version. The only reason i installed with nvm was to get rid of root
user woes.