As per Docker documentation: There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect.
I wish to execute a simple bash script(which processes docker environment variable) before the CMD command(which is init in my case).
Is there any way to do this?
Example of using CMD and ENTRYPOINT together If both ENTRYPOINT and CMD are present, what is written in CMD is executed as an option of the command written in ENTRYPOINT. If an argument is added at the time of docker run , the contents of CMD will be overwritten and the ENTRYPOINT command will be executed.
The ENTRYPOINT instruction looks almost similar to the CMD instruction. However, the main highlighting difference between them is that it will not ignore any of the parameters that you have specified in the Docker run command (CLI parameters).
Step 1: Create a script.sh file and copy the following contents. Step 2: You should have the script.sh is the same folder where you have the Dockerfile. Create the Dockerfile with the following contents which copy the script to the container and runs it part of the ENTRYPOINT using the arguments from CMD.
The CMD command specifies the instruction that is to be executed when a Docker container starts.
Make a custom entrypoint which does what you want, and then exec's your CMD at the end.
NOTE: if your image already defines a custom entrypoint, you may need to extend it rather than replace it, or you may change behavior you need.
entrypoint.sh:
#!/bin/sh ## Do whatever you need with env vars here ... # Hand off to the CMD exec "$@"
Dockerfile:
COPY entrypoint.sh /entrypoint.sh RUN chmod 755 /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"]
Docker will run your entrypoint, using CMD as arguments. If your CMD is init
, then:
/entrypoint.sh init
The exec
at the end of the entrypoint script takes care of handing off to CMD when the entrypoint is done with what it needed to do.
The use of ENTRYPOINT and CMD frequently confuses people new to Docker. In comments, you expressed confusion about it. Here is how it works and why.
The ENTRYPOINT is the initial thing run inside the container. It takes the CMD as an argument list. Therefore, in this example, what is run in the container is this argument list:
# ENTRYPOINT = /entrypoint.sh # CMD = init ["/entrypoint.sh", "init"] # or shown in a simpler form: /entrypoint.sh init
It is not required that an image have an ENTRYPOINT. If you don't define one, Docker has a default: /bin/sh -c
.
So with your original situation, no ENTRYPOINT, and using a CMD of init
, Docker would have run this:
/bin/sh -c 'init' ^--------^ ^--^ | \------- CMD \--------------- ENTRYPOINT
In the beginning, Docker offered only CMD, and /bin/sh -c
was hard-coded as the ENTRYPOINT (you could not change it). At some point along the way, people had use cases where they had to do more custom things, and Docker exposed ENTRYPOINT so you could change it to anything you want.
In the example I show above, the ENTRYPOINT is replaced with a custom script. (Though it is still ultimately being run by sh
, because it starts with #!/bin/sh
.)
That ENTRYPOINT takes the CMD as is argument. At the end of the entrypoint.sh script is exec "$@"
. Since $@
expands to the list of arguments given to the script, this is turned into
exec "init"
And therefore, when the script is finished, it goes away and is replaced by init
as PID 1. (That's what exec
does - it replaces the current process with a different command.)
In the comments, you asked about adding CMD in the Dockerfile. Yes, you can do that.
Dockerfile:
CMD ["init"]
Or if there is more to your command, e.g. arguments like init -a -b
, would look like this:
CMD ["init", "-a", "-b"]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With