Trying to run a pod based on an image with this Dockerfile
:
...
ENTRYPOINT [ "./mybashscript", ";", "flask" ]
CMD [ "run" ]
I would be expecting the full command to be ./mybashscript; flask run
.
However, in this example, the pod
/ container
executes ./mybashscript
but not flask
.
I also tried a couple of variations like:
...
ENTRYPOINT [ "/bin/bash", "-c", "./mybashscript && flask" ]
CMD [ "run" ]
Now, flask
gets executed but run
is ignored.
PS: I am trying to understand why this doesn't work and I am aware that I can fit all into the entrypoint
or shove everything inside the bash
script, but that is not the point.
CodePudding user response:
In both cases you show here, you use the JSON-array exec form for ENTRYPOINT
and CMD
. This means no shell is run, except in the second case where you run it explicitly. The two parts are just combined together into a single command.
The first construct runs the script ./mybashscript
, which must be executable and have a valid "shebang" line (probably #!/bin/bash
). The script is passed three arguments, which you can see in the shell variables $1
, $2
, and $3
: a semicolon ;
, flask
, and run
.
The second construct runs /bin/sh -c './mybashscript && flask' run
. sh -c
takes a single argument, which is mybashscript && flask
; the remaining argument run
is interpreted as a positional argument, and the sh -c
command would see it as $0
.
The arbitrary split of ENTRYPOINT
and CMD
you show doesn't really make sense. The only really important difference between the two is that it is easier to change CMD
when you run the container, for example by putting it after the image name in a docker run
command. It makes sense to put all of the command in the command part, or none of it, but not really to put half of the command in one part and half in another.
My first pass here would be to write:
# no ENTRYPOINT
CMD ./mybashscript && flask run
Docker will insert a sh -c
wrapper for you in bare-string shell form, so the &&
has its usual Bourne-shell meaning.
This setup looks like you're trying to run an initialization script before the main container command. There's a reasonably standard pattern of using an ENTRYPOINT
for this. Since it gets passed the CMD
as parameters, the script can end with exec "$@"
to run the CMD
(potentially as overridden in the docker run
command). The entrypoint script could look like
#!/bin/sh
# entrypoint.sh
./mybashscript
exec "$@"
(If you wrote mybashscript
, you could also end it with the exec "$@"
line, and use that script as the entrypoint.)
In the Dockerfile, set this wrapper script as the ENTRYPOINT
, and then whatever the main command is as the CMD
.
ENTRYPOINT ["./entrypoint.sh"] # must be a JSON array
CMD ["flask", "run"] # can be either form
If you provide an alternate command, it replaces CMD
, and so the exec "$@"
line will run that command instead of what's in the Dockerfile, but the ENTRYPOINT
wrapper still runs.
# See the environment the wrapper sets up
docker run --rm your-image env
# Double-check the data directory setup
docker run --rm -v $PWD/data:/data your-image ls -l /data
If you really want to use the sh -c
form and the split ENTRYPOINT
, then the command inside sh -c
has to read $@
to find its positional arguments (the CMD
), plus you need to know the first argument is $0
and not $1
. The form you show would be functional if you wrote
# not really recommended but it would work
ENTRYPOINT ["/bin/sh", "-c", "./mybashscript && flask \"$@\"", "flask"]
CMD ["run"]