0

I have the following command in my Dockerfile:

RUN echo "\
  export NODE_VERSION=$(\
    curl -sL https://nodejs.org/dist/latest/ |\
    tac |\
    tac |\
    grep -oPa -m 1 '(?<=node-v)(.*?)(?=-linux-x64\.tar\.xz)' |\
    head -1\
  )" >> /etc/bash.bashrc
RUN source /etc/bash.bashrc

The following command should store export NODE_VERSION=6.2.2 in /etc/bash.bashrc, but it's not storing anything.

This works however when I'm inside an image with bash and manually entering the following commands.

Update:

I changed back the shell from bash to the Debian/Ubuntu default dash, which is POSIX standard. I removed this line:

RUN ln -sf /bin/bash /bin/sh && ln -sf /bin/bash /bin/sh.distrib

Than I tried to add to the environment variables with export:

RUN export NODE_VERSION=$(\
  curl -sL https://nodejs.org/dist/latest/ |\
  tac |\
  tac |\
  grep -oPa -m 1 '(?<=node-v)(.*?)(?=-linux-x64\.tar\.xz)' |\
  head -1\
)

But again, the output is missing at image creation, but works when I running the image with $ docker run --rm -it debian /bin/sh. Why?

Update 2:

Looks like the final solution should be something like this:

RUN NODE_VERSION=$( \
  curl -sL https://nodejs.org/dist/latest/ | \
  tac | \
  tac | \
  grep -oPa -m 1 '(?<=node-v)(.*?)(?=-linux-x64\.tar\.xz)' | \
  head -1 \
) && echo $NODE_VERSION

ENV NODE_VERSION $NODE_VERSION

echo $NODE_VERSION returning 6.2.2 as it should at the execution of the Dockerfile also, but ENV NODE_VERSION $NODE_VERSION cannot read this. Is there a way to define variables globally or how can I pass the RUN's output to ENV?

Solution:

I ended up putting the node.js installation part under the same RUN command:

RUN NODE_VERSION=$( \
        curl -sL https://nodejs.org/dist/latest/ | \
        tac | \
        tac | \
        grep -oPa -m 1 '(?<=node-v)(.*?)(?=-linux-x64\.tar\.xz)' | \
        head -1 \
    ) \
    && echo $NODE_VERSION \
    && curl -SLO "https://nodejs.org/dist/latest/node-v$NODE_VERSION-linux-x64.tar.xz" -o "node-v$NODE_VERSION-linux-x64.tar.xz" \
    && curl -SLO "https://nodejs.org/dist/latest/SHASUMS256.txt.asc" \
    && gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \
    && grep " node-v$NODE_VERSION-linux-x64.tar.xz\$" SHASUMS256.txt | sha256sum -c - \
    && tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C /usr/local --strip-components=1 \
    && rm "node-v$NODE_VERSION-linux-x64.tar.xz" SHASUMS256.txt.asc SHASUMS256.txt
4
  • That looks messy in a Dockerfile. Why not place that into a script for the container to run? Commented Jun 20, 2016 at 16:18
  • This is needed for the following URL: https://nodejs.org/dist/latest/node-v$NODE_VERSION-linux-x64.tar.xz which is interpreted to https://nodejs.org/dist/latest/node-v6.2.2-linux-x64.tar.xz for the node.js installation. Unfortunately Node.js repo not offering https://nodejs.org/dist/latest/node-latest-linux-x64.tar.xz archive which will make my question unnecessary. Commented Jun 20, 2016 at 16:22
  • I understand why you need it, but you say it is not storing anything, so does that mean the command is not working within the Dockerfile? If so, again I ask, why not place that command in a bash script for the container to run? Commented Jun 20, 2016 at 16:25
  • I tried it and the output is still empty. I'm running with COPY ./node-version.sh /root/ RUN chmod +x $HOME/node-version.sh; /root/node-version.sh Commented Jun 20, 2016 at 16:37

1 Answer 1

1

Update:
But again, the output is missing at image creation, but works when I running the image with $ docker run --rm -it debian /bin/sh. Why?

This is because each statement (conventionally started with an uppercase verb like RUN, ADD, COPY, ENV, etc) is a brand-new intermediate container.

These intermediate containers do not share the environment (e.g. environment variables) but a Union File System. That is, only data saved in file system and those variables defined in Dockerfile (e.g. through ENV) deliver through intermediate containers. Check out this post and UnionFS Wiki if you want to know how UFS works.

If your goal is to install the latest node each time you build the image. How about having a try for nvm (Node Version Manager)?

ARG UBUNTU=16.04

# Pull base image.
FROM ubuntu:${UBUNTU}

# arguments
  ARG NVM=0.33.9
  ARG NODE=node

# update apt
  RUN apt-get update

# Install curl
  RUN apt-get install -y curl

# Set home for NVM
  ENV NVM_DIR=/home/inazuma/.nvm

# Install Node.js with NVM
  RUN mkdir -p ${NVM_DIR} && \
    curl -o- https://raw.githubusercontent.com/creationix/nvm/v${NVM}/install.sh | bash && \
    . ${NVM_DIR}/nvm.sh && \
    nvm install ${NODE}

# The first following line should always be called in each intermediate container
# to gain nvm, node and npm command
  . ${NVM_DIR}/nvm.sh && nvm use ${NODE} && \
  npm install -g cowsay && \
  cowsay "Making Docker images is really a headache!"

# Set up your PATH for nvm, node and npm command
  CMD ". ${NVM_DIR}/nvm.sh && nvm use ${NODE} && bash"

Note that nvm does not persist across intermediate containers so you should use . ${NVM_DIR}/nvm.sh to set up nvm command for each new intermediate container.

NVM manages node binary locally, use nvm use ${NODE} to include node and npm into PATH. In NVM, node stands for an alias of the latest version of Node; therefore, we set NODE argument to be node (it can also be set to a string of semantic version like 5.0, 9.11.1, etc).

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.