I have an executable C++ application which can only be run and used after sourcing a bash
script in order to set up the shell environment (only Linux systems):
$ . setupenv.sh
$ my_app
Normally, the setupenv.sh script is sourced in the user’s .bashrc or .profile so that they can run the app from the command line.
For a few years I have been generating docker images for my app (as part of CI) with a
Dockerfile which ends with
SHELL ["/bin/bash", "-c"]
CMD source setupenv.sh && my_app
which is OK but I want to be able to do
(1) $ docker run my_docker
(2) $ docker run my_docker bash
(3) $ docker run my_docker [some arguments to be passed to my_app]
With the solution presented above, only (1) works.
(2) launches a bash shell in the container, but the environment is not set: I would want the environment to be set up in this case i.e. have setupenv.sh be executed.
(3) just doesn’t work at all.
I have read and re-read the doc and searched everywhere for answers, I sort of understand that some kind of ENTRYPOINT/CMD combination is required, but I cannot get this to work.
Can anybody help please?
2
Answers
Thanks to the suggestions of @david-maze above, I have got this to work the way I wanted. There are some slight modifications compared to the initial suggestions:
therefore I had to modify the
ENTRYPOINT
command toin case the container is run with e.g.
-w $HOME
(after of course mounting the$HOME
disk inside the container);setupenv.sh
script is strongly bash-dependent, therefore I had to usein the
entrypoint.sh
otherwise the syntax is not understood by/bin/sh
.Finally, in order to treat all 3 of my use cases above, including in fact the 2 versions of case (3) which are (i) passing an argument of type '--option' or (ii) passing an argument which is the name of a data file to open or a macro file to execute, I modified the suggestion of @david-maze like so:
Now I have exactly the behaviour I wanted:
Thank you!
This is a pretty typical use of an entrypoint wrapper script. The basic trick here is that you can specify both an
ENTRYPOINT
and aCMD
, and it’s easier to override theCMD
. Only theENTRYPOINT
runs but it gets passed the (possibly overridden)CMD
as arguments. The (POSIX) shell commandexec "$@"
will replace the current process with the command line from the arguments.So your basic script could look like
In your Dockerfile, make this script be the
ENTRYPOINT
, make the actual thing you want to run be theCMD
, and do not setSHELL
.This should cover your first two cases. If you want to pass additional arguments then the easiest way is to repeat the command.
The script can do whatever it likes, including examining the command before it runs it. The
node
image of note tries to run a command as a Node script if it doesn’t resolve as a command, though this can be confusing. If you want to support passing options without a command, a simpler approach could be to see if it looks like the command starts with an option; for example