3

Is there a way to execute a command as an argument in a Dockerfile ENTRYPOINT? I am creating an image that should automatically run mpirun for the number of processors, i.e., mpirun -np $(nproc) or mpirun -np $(getconf _NPROCESSORS_ONLN).

The following line works:

ENTRYPOINT ["/tini", "--", "mpirun", "-np", "4"] # works

But I cannot get an adaptive form to work:

ENTRYPOINT ["/tini", "--", "mpirun", "-np", "$(nproc)"] # doesn't work
ENTRYPOINT ["/tini", "--", "mpirun", "-np", "$(getconf _NPROCESSORS_ONLN)"] # doesn't work

Using the backtick `nproc` notation does not work either. Nor can I pass an environment variable to the command.

ENV processors 4
ENTRYPOINT ["/tini", "--", "mpirun", "-np", "$processors"] # doesn't work

Has anyone managed to get this kind of workflow?

Gilly
  • 1,739
  • 22
  • 30
  • You might want to create a shell script and start that. You can use ENV variables to control what your shell script does. – Wolfgang Fahl Oct 22 '15 at 06:50

2 Answers2

9

Those likely won't work: see issue 4783

ENTRYPOINT and CMD are special, as they get started without a shell (so you can choose your own) and iirc they are escaped too.

Unlike the shell form, the exec form does not invoke a command shell.
This means that normal shell processing does not happen.

For example, ENTRYPOINT [ "echo", "$HOME" ] will not do variable substitution on $HOME.
If you want shell processing then either use the shell form or execute a shell directly, for example: ENTRYPOINT [ "sh", "-c", "echo", "$HOME" ].

A workaround would be to use a script.

COPY docker-entrypoint.sh /
ENTRYPOINT ["/docker-entrypoint.sh"]

That script, when docker run triggers it, should at least benefit from the environment variable.

See for example the Dockerfile of vromero/activemq-artemis-docker, which runs the script docker-entrypoint.sh.
In order to allow CMD to run as well, the scripts end with:

exec "$@"

(It will execute whatever parameter comes after, either from the CMD directive, or from docker run parameters)


The OP Gilly adds in the comments:

I use in the Dockerfile:

COPY docker-entrypoint.sh
ENTRYPOINT ["/tini", "--", "/docker-entrypoint.sh"] 

And in the entrypoint script:

#!/bin/bash
exec mpirun -np $(nproc) "$@"
hlovdal
  • 26,565
  • 10
  • 94
  • 165
VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • Yes, this works. For any who follow, I use in the Dockerfile: `COPY docker-entrypoint.sh /` `ENTRYPOINT ["/tini", "--", "/docker-entrypoint.sh"]` And in the entrypoint script: `#!/bin/bash` `exec mpirun -np $(nproc) $@` – Gilly Oct 22 '15 at 09:26
  • 1
    @Gilly Great! I have included your comment in the answer for more visibility. – VonC Oct 22 '15 at 10:25
  • Added [quotes for "$@"](https://stackoverflow.com/questions/42298177/docker-container-with-entrypoint-variable-expansion-and-cmd-parameters#comment71978397_42332740) in the answer. – hlovdal Sep 30 '17 at 14:20
2

It is because you are using the exec form for your entry point and variable substitution will not happen in the exec form.

This is the exec form:

ENTRYPOINT ["executable", "param1", "param2"]

this is the shell form:

ENTRYPOINT command param1 param2

From the official documentation:

Unlike the shell form, the exec form does not invoke a command shell. This means that normal shell processing does not happen. For example, ENTRYPOINT [ "echo", "$HOME" ] will not do variable substitution on $HOME

Aurélien Bottazini
  • 3,249
  • 17
  • 26
  • This may work for the environment variables, but does not seem to work for me executing the subcommand. – Gilly Oct 22 '15 at 09:29