dockerfile : npm not found at entrypoint? - node.js

I have this dockerfile :
ARG DEBIAN_FRONTEND=noninteractive
FROM ubuntu:latest
WORKDIR .
COPY . /service/api/
RUN apt-get update -y && apt-get install -y openssl python3 curl
ENV NODE_VERSION 16.19.1
# install nvm
RUN cd / && curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash && cd / && \
export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && nvm install $NODE_VERSION && \
cd /service/api/ && rm -rf node_modules && npm install
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
ADD start.sh /start.sh
#ENTRYPOINT ["tail", "-f", "/dev/null"]
CMD cd /service/api/ && npm start
The image compiles correctly but it can't start because 'npm not found'.
When I uncomment the other debug entrypoint above to exec in the container, I see that npm -v and node -v are available in it.
Why aren't they available in my entrypoint ?

The problem is that RUN ... export NVM_DIR="$HOME/.nvm" does not allow you to use $NVM_DIR later in the Dockerfile to benefit from Docker variables substitutions. Only variables defined by a line starting with ENV can be used later (except when using the variable in a line starting with RUN, but this variable replacement is not implemented by Docker but by a shell). Therefore, your Dockerfile line ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules does not resolve $NVM_DIR to the correct path ($NVM_DIR is simply replaced by an empty string, at this step).
Simply add ENV NVM_DIR /root/.nvm just before ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules and this will correct your Dockerfile.
The correct Dockerfile should be:
ARG DEBIAN_FRONTEND=noninteractive
FROM ubuntu:latest
WORKDIR .
COPY . /service/api/
RUN apt-get update -y && apt-get install -y openssl python3 curl
ENV NODE_VERSION 16.19.1
# install nvm
RUN cd / && curl https://raw.githubusercontent.com/creationix/nvm/master/install.sh | bash && cd / && \
export NVM_DIR="$HOME/.nvm" && [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" && nvm install $NODE_VERSION && \
cd /service/api/ && rm -rf node_modules && npm install
ENV NVM_DIR /root/.nvm
ENV NODE_PATH $NVM_DIR/v$NODE_VERSION/lib/node_modules
ENV PATH $NVM_DIR/versions/node/v$NODE_VERSION/bin:$PATH
ADD start.sh /start.sh
#ENTRYPOINT ["tail", "-f", "/dev/null"]
CMD cd /service/api/ && npm start

Related

Gitlab-ci.yml, SSH and NVM: connect to server via ssh and run nvm use

I have a Node app that uses a specific version of node, so I use nvm to trigger the correct version in the .npmrc file.
The app is deployed with Gitlab. The process is simple: when I push from local to gitlab repo, gitlab will connect to the production server via ssh and pull the latest version of the repo in Gitlab
image: node:latest
before_script:
- apt-get update -qq
- apt-get install -qq git
- 'which ssh-agent || ( apt-get install -qq openssh-client )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$K8S_SECRET_SSH_PRIVATE_KEY" | base64 -d)
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
stages:
- deploy_production
deploy_production:
stage: deploy_production
only:
- master
script:
- ssh myuser#example.com 'export NPM_TOKEN=${NPM_TOKEN} && cd www/myproject && rm -rf node_modules dist/* && git pull && export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use && eval "[ -f .nvmrc ] && nvm install || nvm install stable" && nvm use --delete-prefix && npm ci && npm run prod'
- ssh myuser#example.com "cd www/myproject && nvm use --delete-prefix"
The problem is in the last script. I get this response:
Webpack Bundle Analyzer saved report to /usr/home/myuser/www/myproject/dist/client-report.html
$ ssh myuser#example.com "cd www/myproject && nvm use --delete-prefix"
bash: nvm: command not found
ERROR: Job failed: exit code 1
If I enter directly from my local terminal to the deployment server and ask for the NVM_DIR variable I can get it as expected:
ssh myuser#example.com
cd www/myproject
echo $NVM_DIR
$~/home/myuser/.nvm
But if I add a script to my gitlab-ci.yml with this same action:
image: node:latest
before_script:
- apt-get update -qq
- apt-get install -qq git
- 'which ssh-agent || ( apt-get install -qq openssh-client )'
- eval $(ssh-agent -s)
- ssh-add <(echo "$K8S_SECRET_SSH_PRIVATE_KEY" | base64 -d)
- mkdir -p ~/.ssh
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
stages:
- deploy_production
deploy_production:
stage: deploy_production
only:
- master
script:
- ssh myuser#example.com 'export NPM_TOKEN=${NPM_TOKEN} && cd www/myproject && rm -rf node_modules dist/* && git pull && export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh" --no-use && eval "[ -f .nvmrc ] && nvm install || nvm install stable" && nvm use --delete-prefix && npm ci && npm run prod'
- ssh myuser#example.com "cd www/myproject && echo $NVM_DIR"
- ssh myuser#example.com "cd www/myproject && nvm use --delete-prefix"
The result is empty
[…]
Webpack Bundle Analyzer saved report to /usr/home/myuser/www/myproject/dist/client-report.html
$ ssh myuser#example.com "cd www/myproject && echo $NVM_DIR"
$ ssh myuser#example.com "cd www/myproject && nvm use --delete-prefix"
bash: nvm: command not found
ERROR: Job failed: exit code 1
What can I do to trigger NVM in example.com via ssh in gitlab-ci.yml?
When you log in, your environment (in particular, the variable NVM_PATH but also PATH itself which causes "bash: nvm: command not found") is different than when executing commands with the SSH command. You can check this like so:
ssh myuser#example.com
env
# vs:
ssh myuser#example.com env
The first will execute—depending on what shell and OS you use—files such as .bashrc which execute after an interactive login, the second will (often) not. An excerpt of what NVM adds:
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
The first defines the variable you're missing, the second executes a script that among other things, alters your PATH so that the nvm executable can be found.
You can execute this file manually or add the snippet that NVM adds to your CI pipeline before calling nvm use.

Dockerfile build fails all of a sudden

I'm trying to resolve build problems when running commands to build below dockerfile,
errors for example I get:
1.
/bin/sh: 1: /opt/conda/bin/pip: not found
The command '/bin/sh -c wget -q https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh -O /tmp/miniconda.sh && echo 'd0c7c71cc5659e54ab51f2005a8d96f3 */tmp/miniconda.sh' | md5sum -c - && bash /tmp/miniconda.sh -f -b -p /opt/conda && /opt/conda/bin/conda install --yes -c conda-forge python=3.5 sqlalchemy tornado jinja2 traitlets requests pip pycurl nodejs configurable-http-proxy && /opt/conda/bin/pip install --upgrade pip && rm /tmp/miniconda.sh' returned a non-zero code: 127
2.
When trying to comment the problematic part we get another issue with npm such as:
/bin/sh: 1: npm: not found
Any idea what's going on here?
Dockerfile
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
FROM debian:jessie
MAINTAINER Jupyter Project <jupyter#googlegroups.com>
# install nodejs, utf8 locale, set CDN because default httpredir is unreliable
ENV DEBIAN_FRONTEND noninteractive
RUN REPO=http://cdn-fastly.deb.debian.org && \
echo "deb $REPO/debian jessie main\ndeb $REPO/debian-security jessie/updates main" > /etc/apt/sources.list && \
apt-get -y update && \
apt-get -y upgrade && \
apt-get -y install wget locales git bzip2 &&\
/usr/sbin/update-locale LANG=C.UTF-8 && \
locale-gen C.UTF-8 && \
apt-get remove -y locales && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV LANG C.UTF-8
# install Python + NodeJS with conda
RUN wget -q https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh -O /tmp/miniconda.sh && \
echo 'd0c7c71cc5659e54ab51f2005a8d96f3 */tmp/miniconda.sh' | md5sum -c - && \
bash /tmp/miniconda.sh -f -b -p /opt/conda && \
/opt/conda/bin/conda install --yes -c conda-forge \
python=3.5 sqlalchemy tornado jinja2 traitlets requests pip pycurl \
nodejs configurable-http-proxy && \
/opt/conda/bin/pip install --upgrade pip && \
rm /tmp/miniconda.sh
ENV PATH=/opt/conda/bin:$PATH
EXPOSE 8000
RUN mkdir -p /src/jupyterhub
WORKDIR /src/jupyterhub
ADD . /src/jupyterhub
RUN npm install --unsafe-perm && \
pip install . && \
rm -rf $PWD ~/.cache ~/.npm
ADD . /src/jupyterhub
LABEL org.jupyter.service="jupyterhub"
CMD ["jupyterhub"]
The latest pip package hosted by conda forge is noarch/pip-20.0.2-py_2.tar.bz2 and it has the bin folder missing hence calling /opt/conda/bin/pip will give /opt/conda/bin/pip: not found error.
I would suggest enforcing the versions of the packages to prevent updated versions causing build error, this will achieve deterministic builds in different machines which saves time on having to figure out what version change is causing the error.
In order to get pip properly, amending the Dockerfile with the below should do the trick:
RUN wget -q https://repo.continuum.io/miniconda/Miniconda3-4.2.12-Linux-x86_64.sh -O /tmp/miniconda.sh && \
echo 'd0c7c71cc5659e54ab51f2005a8d96f3 */tmp/miniconda.sh' | md5sum -c - && \
bash /tmp/miniconda.sh -f -b -p /opt/conda && \
/opt/conda/bin/conda install --yes -c conda-forge \
python=3.5 sqlalchemy tornado jinja2 traitlets requests pip=18.0=py35_1001 pycurl \
nodejs configurable-http-proxy && \
/opt/conda/bin/pip install --upgrade pip && \
rm /tmp/miniconda.sh

Docker image erorr bin not found after npm installation

I need to extend a Dockerfile and add grunt to it. I did the following:
This docker run as-is
FROM openjdk:8-jdk-slim
ARG ND=v12.13.0
RUN apt-get update && \
apt-get install --yes --no-install-recommends curl && \
NODE_H=/opt/nodejs; mkdir -p ${NODE_H} && \
curl --fail --silent --output - "http://nodejs.org/dist/${ND}/node-${ND}-linux-x64.tar.gz" \
| tar -xzv -f - -C "${NODE_H}" && \
ln -s "${NODE_H}/node-${ND}-linux-x64/bin/npm" /usr/local/bin/npm && \
ln -s "${NODE_H}/node-${ND}-linux-x64/bin/node" /usr/local/bin/node && \
ln -s "${NODE_H}/node-${ND}-linux-x64/bin/npx" /usr/local/bin/ && \
npm install grunt-cli -g
RUN grunt -v
I've put also the following which doesn't help...
ENV PATH="$PATH:/usr/local/bin"
When I run the command grunt-v I get the following error:
/bin/sh: 1: grunt: not found.
I try also to install grunt through npm install grunt -g without success. Any idea how to fix it?
grunt output from docker build
/opt/nodejs/node-v12.13.0-linux-x64/bin/grunt -> /opt/nodejs/node-v12.13.0-linux-x64/lib/node_modules/grunt-cli/bin/grunt
+ grunt-cli#1.3.2
I need the grunt command to be available in this docker image
I cannot change the docker image, i.e. form jdk...this is given
update
I've also tried with what VonC suggested but still have issue,
FROM openjdk:8-jdk-slim
ARG ND=v12.13.0
RUN apt-get update && \
apt-get install --yes --no-install-recommends curl && \
# install node
NODE_HOME=/opt/nodejs; mkdir -p ${NODE_HOME} && \
curl --fail --silent --output - "http://nodejs.org/dist/${ND}/node-${ND}-linux-x64.tar.gz" \
| tar -xzv -f - -C "${NODE_HOME}" && \
ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/node" /usr/local/bin/node && \
ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/npm" /usr/local/bin/npm && \
ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/npx" /usr/local/bin/ && \
npm install -g grunt-cli
ENV PATH="${PATH}:/usr/local/bin"
RUN ls /usr/local/bin/
RUN grunt -v
the ls command returns
docker-java-home
node
npm
npx
Any idea what is missing?
this will work:
FROM openjdk:8-jdk-slim
ARG ND=v12.13.0
RUN apt-get update && \
apt-get install --yes --no-install-recommends curl \
&& NODE_HOME=/opt/nodejs; mkdir -p ${NODE_HOME} \
&& curl --fail --silent --output - "http://nodejs.org/dist/${ND}/node-${ND}-linux-x64.tar.gz" \
| tar -xzv -f - -C "${NODE_HOME}" \
&& ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/node" /usr/local/bin/node \
&& ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/npm" /usr/local/bin/npm \
&& ln -s "${NODE_HOME}/node-${ND}-linux-x64/bin/npx" /usr/local/bin/ \
&& npm install --prefix /usr/local/ -g grunt-cli
ENV PATH="${PATH}:/usr/local/bin"
RUN ls /usr/local/bin
RUN grunt -v
using --prefix will tell npm to install grunt in /usr/local/bin
ls output:
Step 5/6 : RUN ls /usr/local/bin
---> Running in 96493743512d
docker-java-home
grunt
node
npm
npx
grunt -v output:
Step 6/6 : RUN grunt -v
---> Running in c6248c4fce6c
grunt-cli: The grunt command line interface (v1.3.2)
I've put also the following which doesn't help...
ENV PATH="$PATH:/usr/local/bin"
As illustrated here, that should be enough, also the exact syntax would be (to be sure)
ENV PATH="${PATH}:/usr/local/bin"
But:
make sure to add it just before your last RUN grunt
add a RUN ls /usr/local/bin/ to see if your install command worked
try and use the syntax npm instal -g grunt, instead of npm instal grunt -g
Another approach:
The Docker image openjdk:8-jdk-slim is based on debian:buster-slim
So try and install node through its installation script, as seen here:
# install node.js environment
RUN apt-get update && \
apt-get install -y --no-install-recommends \
gnupg && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
RUN curl -sL https://deb.nodesource.com/setup_${NODEJS_VERSION}.x | bash -
RUN apt-get update && \
apt-get install -y --no-install-recommends \
nodejs && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* && \
npm install -g grunt
You can still use the same base image openjdk:8-jdk-slim, but you just extend it with a regular node installation, rather than fiddling with symbolic links.
In your case, add ENV NODEJS_VERSION 12 first.
This works
FROM openjdk:8-jdk-slim
ARG NODE_HOME=/opt/nodejs
ARG ND=v12.13.0
ENV PATH=${PATH}:${NODE_HOME}/node-${ND}-linux-x64/bin/
RUN apt-get update && \
apt-get install --yes --no-install-recommends curl && \
# install node
mkdir -p ${NODE_HOME} && \
curl --fail --silent --output - "http://nodejs.org/dist/${ND}/node-${ND}-linux-x64.tar.gz" \
| tar -xzv -f - -C "${NODE_HOME}" && \
npm install -g grunt-cli
RUN grunt -v
First, move NODE_HOME up in your dockerfile and set it as a build arg.
That way we can already set the PATH early on.
By setting the path to the node bin folder we can use all binaries in that location without manually linking each. That translates to grunt being available after installation without additional black magic.

Laravel Mix on Docker: ETXTBSY: text file is busy

I am trying to run Laravel Mix on my Docker container.
I have managed to install the latest versions of npm and node (thanks Laradock).
Now when I try and run npm install I get lots of these:
npm WARN rollback Rolling back express#4.16.3 failed (this is probably harmless): ETXTBSY: text file is busy, unlink '/srv/app/node_modules/express/package.json.3619593601'
npm WARN rollback Rolling back array-flatten#1.1.1 failed (this is probably harmless): ETXTBSY: text file is busy, unlink '/srv/app/node_modules/express/node_modules/array-fla
tten/package.json.2934324270'
node:v10.5.0
npm:v6.1.0
Windows host.
Guest is: Linux 2369f4b16e52 4.9.93-boot2docker #1 SMP Thu May 10 16:27:54 UTC 2018 x86_64 GNU/Linux
Dockerfile:
# this is the DEV/LOCAL dockerfile (default)
FROM php:7.2-apache
COPY apache/vhost.conf /etc/apache2/sites-available/000-default.conf
# Get an update, install some bits
RUN apt-get -yqq update \
&& apt-get -yqq install --no-install-recommends apt-utils unzip libzip-dev
RUN docker-php-ext-install pdo_mysql opcache zip \
&& a2enmod rewrite negotiation
ARG DOCKER_ENV=${DOCKER_ENV}
#if we are in dev, we need xdebug
RUN if [ ${DOCKER_ENV} = local ] || [ ${DOCKER_ENV} = dev ] || [ ${DOCKER_ENV} = development ]; then \
pecl install xdebug-2.6.0 \
&& docker-php-ext-enable xdebug \
; fi
#copy our php.ini over and the composer details
COPY php/*.ini /usr/local/etc/php/conf.d/
COPY composer/composer-install.sh /tmp/composer-installer.sh
WORKDIR /tmp
#if we are in dev, run the Composer install
RUN if [ ${DOCKER_ENV} = local ] || [ ${DOCKER_ENV} = dev ] || [ ${DOCKER_ENV} = development ]; then \
apt-get -yqq install --no-install-recommends git \
&& chmod +x composer-installer.sh \
&& ./composer-installer.sh \
&& mv composer.phar /usr/local/bin/composer \
&& chmod +x /usr/local/bin/composer \
&& su -l www-data -s /bin/sh -c "composer --version" \
; fi
#Need these for Laravel Mix (compiling assets) - stolen from Laradock
###########################################################################
# Node / NVM:
###########################################################################
# Check if NVM needs to be installed
ARG NODE_VERSION=stable
ENV NODE_VERSION ${NODE_VERSION}
ARG INSTALL_NODE=true
ARG INSTALL_NPM_GULP=true
ARG INSTALL_NPM_BOWER=true
ARG INSTALL_NPM_VUE_CLI=true
ARG NPM_REGISTRY
ENV NPM_REGISTRY ${NPM_REGISTRY}
ENV NVM_DIR ${PROJECT_PATH}/.nvm
RUN if [ ${INSTALL_NODE} = true ]; then \
# Install nvm (A Node Version Manager)
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash \
&& . $NVM_DIR/nvm.sh \
&& nvm install ${NODE_VERSION} \
&& nvm use ${NODE_VERSION} \
&& nvm alias ${NODE_VERSION} \
&& if [ ${NPM_REGISTRY} ]; then \
npm config set registry ${NPM_REGISTRY} \
;fi \
&& if [ ${INSTALL_NPM_GULP} = true ]; then \
npm install -g gulp \
;fi \
&& if [ ${INSTALL_NPM_BOWER} = true ]; then \
npm install -g bower \
;fi \
&& if [ ${INSTALL_NPM_VUE_CLI} = true ]; then \
npm install -g vue-cli \
;fi \
;fi
# Wouldn't execute when added to the RUN statement in the above block
# Source NVM when loading bash since ~/.profile isn't loaded on non-login shell
RUN if [ ${INSTALL_NODE} = true ]; then \
echo "" >> ~/.bashrc && \
echo 'export NVM_DIR="$HOME/.nvm"' >> ~/.bashrc && \
echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.bashrc \
;fi
# Add NVM binaries to root's .bashrc
USER root
RUN if [ ${INSTALL_NODE} = true ]; then \
echo "" >> ~/.bashrc && \
echo 'export NVM_DIR="/home/laradock/.nvm"' >> ~/.bashrc && \
echo '[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" # This loads nvm' >> ~/.bashrc \
;fi
# Add PATH for node
ENV PATH $PATH:$NVM_DIR/versions/node/v${NODE_VERSION}/bin
RUN if [ ${NPM_REGISTRY} ]; then \
. ~/.bashrc && npm config set registry ${NPM_REGISTRY} \
;fi
WORKDIR /srv/app
ps fax gives:
PID TTY STAT TIME COMMAND
21 pts/0 Ss 0:00 bash
300 pts/0 R+ 0:00 \_ ps fax
1 ? Ss 0:00 apache2 -DFOREGROUND
16 ? S 0:00 apache2 -DFOREGROUND
17 ? S 0:00 apache2 -DFOREGROUND
18 ? S 0:00 apache2 -DFOREGROUND
19 ? S 0:00 apache2 -DFOREGROUND
20 ? S 0:00 apache2 -DFOREGROUND
Is it something to do with this:
"boot2docker is based on VirtualBox. Virtualbox does not allow symlinks on shared folders for security reasons."
Performing a npm install via Docker on a windows host
It looks like npm config set registry ${NPF_REGISTRY} didn't finished, so, maybe that's reason why your npm install finds ETXTBSY.
Try to remove from Dockerfile RUN if [ ${NPM_REGISTRY} ]; then \
. ~/.bashrc && npm config set registry ${NPM_REGISTRY} \
;fi
and execute it manually before npm install and see what happens.

Docker, running NVM script in a new bash shell

I have the following in my Dockerfile:
run apt-get update; \
apt-get install -y curl && \
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.5/install.sh | bash
Following this line of code, I need to run a command in a new bash shell so that the environment variable set from the NVM script are used.
I have tired the following to install Nodejs and it does not work:
run ["/bin/bash", "-c", "nvm install 8.7.0"]
What can I do?
It's better to use a Dockerhub repo and use it in your Dockerfile.
You can check this repositorie or this link for more repositories, please read description before choosing a repositorie.
So for example, you can add the code line below in your Dockerfile it will pull the nvm image and install it then add your app instructions.
FROM livingdocs/nvm
Or you can read their Dockerfile and use the command they used it to install nvm
ADD ./.nvmrc /app/.nvmrc
RUN bash -c '. /usr/share/nvm/nvm.sh && cd /app && nvm install && nvm alias default'
if it didn't put this one from another repositorie:
RUN sudo apt-get update && \
sudo apt-get install -y build-essential libssl-dev libmysqlclient-dev && \
sudo apt-get clean && \
sudo rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN curl --location https://raw.github.com/creationix/nvm/master/install.sh | sh && \
sudo /bin/bash -c "echo \"[[ -s \$HOME/.nvm/nvm.sh ]] && . \$HOME/.nvm/nvm.sh\" >> /etc/profile.d/npm.sh" && \
echo "[[ -s $HOME/.nvm/nvm.sh ]] && . $HOME/.nvm/nvm.sh" >> $HOME/.bashrc

Resources