简体   繁体   中英

CMD and ENTRYPOINT with script, same Dockerfile

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 ./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.

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"]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM