Why both CMD and entrypoint defined in some images? [duplicate] - docker

This question already has answers here:
What is the difference between CMD and ENTRYPOINT in a Dockerfile?
(19 answers)
Closed 1 year ago.
I have seen some images that based on the inspect have both CMD and ENTRYPOINT set.
What is the idea of this? What use cases are served when both are set?

per https://docs.docker.com/engine/reference/builder/#cmd
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
this means that CMD can be used as a list of parametres to the entrypoint.
UPD 1
the idea here is that you can specify the entrypoint (binary to run at start) and then have CMD parameters to this entrypoint which can be overridden.
UPD 2
Here is an example:
cat Dockerfile
FROM busybox
ENTRYPOINT ["ls"]
CMD ["etc"]
now that if you build the image and run it without any arguments, it will product the list with the content of etc folder
$ docker run lister
group
hostname
hosts
localtime
mtab
network
passwd
resolv.conf
shadow
if you do specify the arguments though, you can override the CMD and list the content of a different folder
$ docker run lister var
spool
www
so the executable stays the same in both cases, while the CMD in the Dockerfile is defining the default argument to this binary. Then we can override when we run the container.

Related

How to pass arguments to a docker container without specifying a CMD

Currently if I run a container I must speicfy a new CMD in order to pass args.
I.e. the format is docker run image [CMD] [ARGS]
Is there any way to pass args to the CMD at the end of the Dockerfile without specifying a new CMD when running the container.
The reason this probably works for you is that usually, the default ENTRYPOINT is /bin/bash -c, and then when you add CMD with executable it adds to the ENTRYPOINT to run the CMD contents as you'd expect.
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
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.
Dockerfile docs
This means your main option is to replace the old CMD with an ENTRYPOINT in the new Dockerfile and append the runtime arguments with a new CMD directive, either with permanent default values, ones received from environment variables, or a combination of the two
Hopes this helps
You can write your CMD statement like this at end of the Dockerfile.
CMD ["executable","param1","param2"]
source: https://docs.docker.com/engine/reference/builder/

How does a docker container from SCRATCH execute a binary?

The docker documentation says that you can build this minimal image:
FROM scratch
ADD hello /
CMD ["/hello"]
Presumably the way this works is that the CMD step is using the default shell (that is, bin/sh, per https://stackoverflow.com/a/21564990/10900852) to run the hello executable.
But if SCRATCH is really entirely empty, where is bin/sh coming from? Why does my image contain a shell?
A container built from scratch does NOT have anything inside at the beginning, so your image contains no /bin/sh.
However, there are two formats of CMD which matters here:
CMD ["/hello"]
CMD /hello
The first format specifies a full command and is called directly via execve(2). The actual process executed is as exactly as ["/hello"] (i.e. argc == 1)
The second format specifies a "entrypoint parameter" and is passed as a single argument to entrypoint, so Docker will attempt to run ["/bin/sh", "-c", "/hello"] with argc == 3 and fail.
You can replace the CMD line with CMD /hello and observe it for yourself.

Is CMD or ENTRYPOINT necessary to mention in Dockerfile?

I have read the docs about CMD and ENTRYPOINT
https://docs.docker.com/engine/reference/builder/#entrypoint
Here, they have mentioned in the table that "NO CMD and NO ENTYRPOINT is not allowed", But I created a Dockerfile without CMD and ENTRYPOINT and the image was built successfully.
Download alpine tar from here Alpine Tar
Dockerfile
from scratch
ADD alpine-minirootfs-3.11.2-x86_64.tar.gz /
COPY . /
Building the image:
docker build -t test:1 .
Sending build context to Docker daemon 2.724MB
Step 1/3 : from scratch
-----
Successfully tagged test:1
docker run -ti test:1 /bin/sh
/ #
It worked!! So why in the docs it's mentioned that either CMD or ENTRYPOINT is necessary?
Specifying a command at the end of the docker run command line supplies (or overrides) CMD; similarly, the docker run --entrypoint option supplies (or overrides) ENTRYPOINT. In your example you gave a command /bin/sh so there's something for the container to do; if you leave it off, you'll get an error.
As a matter of style your Dockerfiles should almost always declare a CMD, unless you're extending a base image that's already running the application automatically (nginx, tomcat). That will let you docker run the image and launch the application embedded in it without having to remember a more specific command-line invocation.
The following line from documentation is incorrect.
Dockerfile should specify at least one of CMD or ENTRYPOINT commands.
It should probably say -
CMD or ENTRYPOINT is necessary for running a container.

Passing multiple classFile as argument to Dockerfile

I have a Dockerfile like this:
FROM java:8
ARG cName
ADD target/jar1.jar p2p.jar
ADD ci/docker_entrypoint.sh .
CMD ["bash", "docker_entrypoint.sh" , "$cName"]
I have a docker_entrypoint.sh which look :
java -cp p2p.jar $1
I have multiple classes to run and I am providing className as input parameter to dockerfile. I am running couple of commands to build and run docker.
docker build -f Dockerfile -t docker-p2p --build-arg cName=com.HelloWorld .
docker run docker-p2p
after running the second command I am getting below error:
Error: Could not find or load main class $cName
I am new to docker and I am not able to parameterise by dockerfile but when I mention a className "HelloWorld" in the dockerfile, it runs well. But when I try to pass parameters , it throws me out with this error.
You have to differ between docker run, cmd and entrypoint.
For your example you can use an entrypoint and set the parameter via an environment variable.
One simple and easy Dockerfile example could be:
FROM java:8
ENV NAME="John Dow"
ENTRYPOINT ["/bin/bash", "-c", "echo Hello, $NAME"]
with docker build . -t test and docker run -e NAME="test123" test
Also have a look at some further docu: docker-run-vs-cmd-vs-entrypoint.
If you do wind up with a Docker image that can do multiple things, it's a little unusual to create one image per task the way you're describing. You can pass additional command-line parameters in docker run or most other ways to start a container, and you can use that to control what the image does.
For example, you might want to set up your image so that you can run
docker run ... docker-p2p com.HelloWorld
passing the class name as an argument. I'd write an entrypoint script that wrapped this in a java call if appropriate (but passed through non-class names, like docker run ... sh):
#!/bin/sh
set -e
case "$1" of
com.*) exec java "$#" ;;
*) exec "$#" ;;
esac
The corresponding Dockerfile doesn't take any ARGs; it could be
FROM java:8
# I prefer COPY to ADD, unless you explicitly want automatic
# HTTP fetches and/or tar file extraction.
COPY target/jar1.jar /p2p.jar
COPY ci/docker_entrypoint.sh /
# Globally set the class path. (A Docker image only does one thing.)
ENV CLASSPATH /p2p.jar
# Always launch the entrypoint script.
ENTRYPOINT ["/docker_entrypoint.sh"]
# Give a default command, which with our script is a class name.
CMD ["com.HelloWorld"]
If you actually want a container per task, you could create a base image that contained everything up to the ENTRYPOINT line, and then created derived images FROM that base image that just set a different CMD.

Why is docker still running CMD when overridden in by docker run?

I have a Dockerfile with the following CMD as the last line
CMD ["/usr/local/myapp/bin/startup.sh", "docker"]
Part of a script that is executed against the docker image during startup is as follows
# find directory of cacerts file in DOCKER_JAVA_HOME of container
DOCKER_CACERTS_DIR=$(dirname "$(docker run "$DOCKER_IMAGE_ID" find "$DOCKER_JAVA_HOME" -name cacerts)")
However, this still executes the CMD line from my Dockerfile.
I have found that I can alter this behaviour by changing the line in the script as follows.
# find directory of cacerts file in DOCKER_JAVA_HOME of container
DOCKER_CACERTS_DIR=$(dirname "$(docker run --entrypoint find "$DOCKER_IMAGE_ID" "$DOCKER_JAVA_HOME" -name cacerts)")
However, I didn't think this would be necessary. Is it normal for docker to execute the CMD when overridden in the docker run command? I thought this was supposed to be one of the differences between using CMD and ENTRYPOINT, that you could easily override CMD without using the --entrypoint flag.
In case it's important, this is using docker version 17.03.0-ce
The image being run has an ENTRYPOINT defined somewhere. Probably in the image you are building FROM if there isn't one in your Dockerfile.
When ENTRYPOINT and CMD are defined, Docker will pass the CMD to the ENTRYPOINT as arguments. From there, it's up to the ENTRYPOINT executable to decide what to do.
The arguments could be ignored completely, modified as the entry point sees fit or it can pass the complete command on to be run. That behaviour is image specific.

Resources