21

I have a bash function nvm defined in /root/.profile. docker build failed to find that function when I call it in RUN step.

RUN apt-get install -y curl build-essential libssl-dev && \
    curl https://raw.githubusercontent.com/creationix/nvm/v0.16.1/install.sh | sh
RUN nvm install 0.12 && \
    nvm alias default 0.12 && \
    nvm use 0.12

The error is

Step 5 : RUN nvm install 0.12
 ---> Running in b639c2bf60c0
/bin/sh: nvm: command not found

I managed to call nvm by wrapping it with bash -ic, which will load /root/.profile.

RUN bash -ic "nvm install 0.12" && \
    bash -ic "nvm alias default 0.12" && \
    bash -ic "nvm use 0.12"

The above method works fine, but it has a warning

bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell

And I want to know is there a easier and cleaner way to call the bash function directly as it's normal binary without the bash -ic wrapping? Maybe something like

RUN load_functions && \
    nvm install 0.12 && \
    nvm alias default 0.12 && \
    nvm use 0.12
Quanlong
  • 24,028
  • 16
  • 69
  • 79
  • `RUN bash -c 'nvm install 0.12 && nvm alias default 0.12 && nvm use 0.12'` should do the trick. Does it work for you? (I'm not 100% sure because I don't know how your container is looking in detail) – hek2mgl Sep 22 '15 at 03:24
  • It works fine. But I am looking for a better solution. – Quanlong Sep 22 '15 at 03:28
  • Ok, check my answer. A shell script is the cleanest way to do it. – hek2mgl Sep 22 '15 at 03:32
  • You've not accepted my answer so far. What do you mean with a *better* solution? – hek2mgl Sep 22 '15 at 05:02
  • [NVM](https://github.com/creationix/nvm) is not designed for Docker. Do you really want two Node.js in a single container? – Franklin Yu Nov 08 '16 at 05:39

1 Answers1

21

Docker's RUN doesn't start the command in a shell. That's why shell functions and shell syntax (like cmd1 && cmd2) cannot being used out of the box. You need to call the shell explicitly:

RUN bash -c 'nvm install 0.12 && nvm alias default 0.12 && nvm use 0.12'

If you are afraid of that long command line, put those commands into a shell script and call the script with RUN:

script.sh

#!/bin/bash

nvm install 0.12 && \
nvm alias default 0.12 && \
nvm use 0.12

and make it executable:

chmod +x script.sh

In Dockerfile put:

RUN /path/to/script.sh
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • I need run nvm in some different steps. And I think the right quote of `bash -c` is hard to control when commands are formatted as multiple lines. – Quanlong Sep 22 '15 at 09:00
  • 1
    That's why I've suggested to use a shell script. – hek2mgl Sep 22 '15 at 18:40
  • I don't get why you need multiple scripts. Can you elaborate on that? Once I got it I may suggest something. – hek2mgl Sep 22 '15 at 19:11
  • 6
    This is not what I got from [documentation](https://docs.docker.com/engine/reference/builder/#/run): "`RUN ` (*shell* form, the command is run in a shell, which by default is `/bin/sh -c` on Linux or `cmd /S /C` on Windows)". – Franklin Yu Nov 08 '16 at 04:43
  • 1
    yeah I am not sure this answer is right...I was under the impression that each `RUN` command executed its contents in a subshell. – Alexander Mills May 14 '18 at 06:05
  • @AlexanderMills Thanks for letting me know! (overlooked the previous comment) Yeah, this answer is wrong. Will try to reproduce the problem and fix the answer ... – hek2mgl May 14 '18 at 07:15
  • your answer actually might be right, given what I've read here: https://stackoverflow.com/questions/20635472/using-the-run-instruction-in-a-dockerfile-with-source-does-not-work – Alexander Mills May 14 '18 at 07:19
  • :) It is at least not wrong, but normally a single `RUN` command should be enough. Let me try to reproduce it. Probably just my phrasing was wrong or not clear enough – hek2mgl May 14 '18 at 07:21