4
FROM some-build:latest as build

COPY / /var/www/html

WORKDIR /var/www/html
RUN cd /var/www/html && composer install

FROM some-build2:latest as run

COPY --from=build /var/www/html /var/www/html

ENV PATH ${HOME}/local/bin:${PATH}:/home/site/wwwroot

RUN cd /var/www/html && \
    npm install && \
    npm run production

ENTRYPOINT ["/bin/init_container.sh"]

The image run contains an installed npm. Despite this fact, the npm install return the error: /bin/sh: 1: npm: not found

How is this possible? What am I doing wrong?


Edit:

As answer to @BMitch 's comment, when I run the RUN image, in the container the node is on the PATH and I can use it. The path is /root/local/bin. I've attached all the Dockerfiles.

I have 3 docker files:
APP
The one you've already seen before.

RUN

FROM php:7.2.5-apache
MAINTAINER Azure App Services Container Images <appsvc-images@microsoft.com>

COPY apache2.conf /bin/
COPY init_container.sh /bin/

RUN a2enmod rewrite expires include deflate

# install the PHP extensions we need
RUN apt-get update \
    && apt-get install -y --no-install-recommends \
     libpng-dev \
     libjpeg-dev \
     libpq-dev \
     libldap2-dev \
     libldb-dev \
     libicu-dev \
     libgmp-dev \
     mysql-client \
     libmagickwand-dev \
     openssh-server vim curl wget tcptraceroute \
    && chmod 755 /bin/init_container.sh \
    && echo "root:Docker!" | chpasswd \
    && echo "cd /home" >> /etc/bash.bashrc \
    && ln -s /usr/lib/x86_64-linux-gnu/libldap.so /usr/lib/libldap.so \
    && ln -s /usr/lib/x86_64-linux-gnu/liblber.so /usr/lib/liblber.so \
    && ln -s /usr/include/x86_64-linux-gnu/gmp.h /usr/include/gmp.h \
    && rm -rf /var/lib/apt/lists/* \
    && pecl install imagick-beta \
    && docker-php-ext-configure gd --with-png-dir=/usr --with-jpeg-dir=/usr \
    && docker-php-ext-configure pdo_mysql --with-pdo-mysql=mysqlnd \
    && docker-php-ext-configure mysqli --with-mysqli=mysqlnd \
    && docker-php-ext-install gd \
     mysqli \
     opcache \
     pdo \
     pdo_mysql \
     pdo_pgsql \
     pgsql \
     ldap \
     intl \
     gmp \
     zip \
     bcmath \
     mbstring \
     pcntl \
     xml \
     xmlrpc \
    && docker-php-ext-enable imagick

###################
# Installing node #
###################

RUN apt-get update -yq && apt-get upgrade -yq && \
apt-get install -yq g++ libssl-dev apache2-utils curl git python make nano

# setting up npm for global installation without sudo
# http://stackoverflow.com/a/19379795/580268
RUN MODULES="local" && \
    echo prefix = ~/$MODULES >> ~/.npmrc && \
    echo "export PATH=\$HOME/$MODULES/bin:\$PATH" >> ~/.bashrc && \
    . ~/.bashrc && \
    mkdir ~/$MODULES && \
\
# install Node.js and npm
# https://gist.github.com/isaacs/579814#file-node-and-npm-in-30-seconds-sh
    mkdir ~/node-latest-install && cd $_ && \
    curl http://nodejs.org/dist/v8.11.3/node-v8.11.3.tar.gz | tar xz --strip-components=1 && \
    ./configure --prefix=~/$MODULES && \
    make install && \
    curl -L https://www.npmjs.org/install.sh | sh

# optional, check locations and packages are correct
# RUN which node; node -v; which npm; npm -v; \
#   npm ls -g --depth=0

# Remove unnecessary packages
# RUN apt-get -yq purge g++ libssl-dev curl git python make nano
# RUN apt-get -yq autoremove

###################

RUN   \
   rm -f /var/log/apache2/* \
   && rmdir /var/lock/apache2 \
   && rmdir /var/run/apache2 \
   && rmdir /var/log/apache2 \
   && chmod 777 /var/log \
   && chmod 777 /var/run \
   && chmod 777 /var/lock \
   && chmod 777 /bin/init_container.sh \
   && cp /bin/apache2.conf /etc/apache2/apache2.conf \
   && rm -rf /var/www/html \
   && rm -rf /var/log/apache2 \
   && mkdir -p /home/LogFiles \
   && ln -s /home/LogFiles /var/log/apache2 


RUN { \
        echo 'opcache.memory_consumption=128'; \
        echo 'opcache.interned_strings_buffer=8'; \
        echo 'opcache.max_accelerated_files=4000'; \
        echo 'opcache.revalidate_freq=60'; \
        echo 'opcache.fast_shutdown=1'; \
        echo 'opcache.enable_cli=1'; \
    } > /usr/local/etc/php/conf.d/opcache-recommended.ini

RUN { \
        echo 'error_log=/var/log/apache2/php-error.log'; \
        echo 'display_errors=Off'; \
        echo 'log_errors=On'; \
        echo 'display_startup_errors=Off'; \
        echo 'date.timezone=UTC'; \
    } > /usr/local/etc/php/conf.d/php.ini


COPY sshd_config /etc/ssh/

EXPOSE 2222 8080

ENV APACHE_RUN_USER www-data
ENV PHP_VERSION 7.2.5

ENV PORT 8080
ENV WEBSITE_ROLE_INSTANCE_ID localRoleInstance
ENV WEBSITE_INSTANCE_ID localInstance
ENV PATH ${PATH}:/home/site/wwwroot

ENTRYPOINT ["/bin/init_container.sh"]

BUILD

FROM composer:latest as composer

FROM php:7.2.5-apache as apache

COPY --from=composer /usr/bin/composer /usr/bin/composer

RUN apt-get update && \
apt-get install git zip unzip -y

Edit 2:
It is important that if I remove the RUN npm... commands, then the whole build is a success and the result image contains the npm and I can use it (I've verified by using a container in interactive mode).


Edit 3:
Here's a lot lot simpler solution that can be tried out instantly:

FROM alpine as img1
RUN echo "$HOME" > $HOME/test.txt

FROM alpine as img2
RUN cat $HOME/test.txt

The result is: cat: can't open '/root/test.txt': No such file or directory

Infinite Possibilities
  • 7,415
  • 13
  • 55
  • 118

1 Answers1

2

Two issues going on here. The "php:7.2.5-apache" image won't have /root/local/bin in the path, and you did not add it to the path during your build. The npm commands will work when you login interactively likely because of some changes to the shell login scripts that setup the environment. You'll need to run these environment setup scripts before running any npm commands, and that must be done within the same RUN command. To verify for yourself, you can check your .bashrc for variables or commands run to setup the npm environment. And you can verify the environment is different by comparing the PATH value with an env command in the interactive shell and in your build, you should see two different outputs if this is your issue. When I ran part of your run image, I saw the following in the .bashrc:

export PATH=$HOME/local/bin:$PATH

So you'll want to update the line in your Dockerfile for the run image:

ENV PATH /root/local/bin:${PATH}:/home/site/wwwroot

Per your edit 3, that's an entirely different issue. You created a file in one new image, and then went back to the base image where the file doesn't exist. If you wanted to see the file in a multi-stage build, then you either need to copy it between the stages, or use the previous image as your "from".

FROM alpine as img1
RUN echo "$HOME" > $HOME/test.txt

FROM alpine as img2
COPY --from=img1 /root/test.txt /root/test.txt
RUN cat $HOME/test.txt

or

FROM alpine as img1
RUN echo "$HOME" > $HOME/test.txt

FROM img1 as img2
RUN cat $HOME/test.txt
BMitch
  • 231,797
  • 42
  • 475
  • 450
  • Ok, let me check it. Until, a small clarification: I just started to use docker, so I am not sure if I understand the difference between interactive shell and my build. Maybe it sounds badly, but what I thought is that I can have an interactive shell to my build. This means I am totally wrong. Can you please point me to the right direction? – Infinite Possibilities Jul 27 '18 at 13:18
  • @InfinitePossibilities a docker build is not interactive. You can run any image, output from a build, with the interactive option. And if there's a shell inside that image, you can run that interactively. – BMitch Jul 27 '18 at 13:27
  • Exactly this is how I thought then, but I had the impression that all the images have a shell. Thanks for the clarification. I added the ENV (as you can see in my edit), but the result is the same. I also verified the bashrc file, but it doesn't contain anything else than this PATH setting. – Infinite Possibilities Jul 27 '18 at 15:11
  • @InfinitePossibilities replace your `npm` command with an `env` and compare the path value. One thought is that `$HOME` may not be defined, so try expanding that too. – BMitch Jul 27 '18 at 15:13
  • Finally, you are right, I changed npm to env and that PATH is different than what I set with the ENV command and also different than what I have in the "run" image. To avoid this, I used absolute path to run npm. In the "run" image, npm is at the path /root/local/bin. When I call the FROM for the run image, shouldn't be the npm at the same path? – Infinite Possibilities Jul 27 '18 at 15:25
  • @InfinitePossibilities yes, npm will be in the same directory from the parent image. – BMitch Jul 27 '18 at 16:11
  • Ok, man, after I entered the correct path to ENV, everything worked fine. Awesome! Don't really know why it wasn't working when I expanded the path in the run command without the ENV command, but I think I have to dig deeper. – Infinite Possibilities Jul 27 '18 at 16:12