Install nodejs and npm in Dockerfile

Viewed 14716

The context

I have a Dockerfile to create an image that contains an apache webserver. However I also want to build my website using the Dockerfile so that the build process isn't dependent on the developers local environment. Note that the docker container is only going to be used for local development not for production.

The problem

I have this Dockerfile:

FROM httpd
RUN apt-get update -yq
RUN apt-get -yq install curl gnupg
RUN curl -sL https://deb.nodesource.com/setup_12.x | bash
RUN apt-get update -yq
RUN apt-get install -yq \
        dh-autoreconf=19 \
        ruby=1:2.5.* \
        ruby-dev=1:2.5.* \
        nodejs

I build it:

sudo docker build --no-cache .

The build completes successfully, here is part of the output:

Step 9/15 : RUN curl -sL https://deb.nodesource.com/setup_12.x | bash
 ---> Running in e6c747221ac0
......
......
......
Removing intermediate container 5a07dd0b1e01
 ---> 6279003c1e80
Successfully built 6279003c1e80

However, when I run the image in a container using this:

sudo docker container run --rm -it --name=debug 6279003c1e80 /bin/bash

Then when doing apt-cache policy inside the container, it doesn't show the repository that should have been added with the curl command. Also when doing apt-cache policy nodejs it shows the old version is installed.

However when I then run the following inside the container:

curl -sL https://deb.nodesource.com/setup_12.x | bash
apt-cache policy
apt-cache policy nodejs

It shows me the repository is added and it shows the newer nodejs version is available.

So why is it that when using the curl command using RUN inside the docker file it doesn't seem to work, but when doing it manually in the container from a shell then it does work? And how can I get around this problem?

Updates

  • Note that to prevent caching issues I am using the --no-cache flag.
  • I also removed all containers and did sudo docker system prune and rebuild the image but without success.
  • I tried bundling everything in one RUN command as user "hmm" suggested (as this is best practice for apt commands):
RUN apt-get update -yq \
    && apt-get -yq install curl gnupg && \
    && curl -sL https://deb.nodesource.com/setup_12.x | bash \
    && apt-get update -yq \
    && apt-get install -yq \
        dh-autoreconf=19 \
        ruby=1:2.5.* \
        ruby-dev=1:2.5.* \
        nodejs \
    && rm -rf /var/lib/apt/lists/*
1 Answers

You're likely running into issues with cached layers. There's a long section in the Dockerfile best practices documentation on using apt-get. Probably worth a read.

The gist is that Docker doesn't recognize any difference between the first and second RUN apt-get update, nor does it know that apt-get install depends on a fresh apt-get update layer.

The solution is to combine all of that into a single RUN command (recommended) or disable the cache during the build process (docker build --no-cache).

RUN apt-get update -yq \
    && apt-get -yq install curl gnupg ca-certificates \
    && curl -L https://deb.nodesource.com/setup_12.x | bash \
    && apt-get update -yq \
    && apt-get install -yq \
        dh-autoreconf=19 \
        ruby=1:2.5.* \
        ruby-dev=1:2.5.* \
        nodejs

Edit: Running your Dockerfile locally, I noticed no output from the curl command. After removing the -s flag (fail silently), you can see it's failing due to not being able to verify the server's SSL certificate:

curl: (60) SSL certificate problem: unable to get local issuer certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

The solution to that issue is to install ca-certificates before running curl. I've updated the RUN command above.

Related