This is a good article http://www.johnzaccone.io/entrypoint-vs-cmd-back-to-basics/
explaining the difference between ENTRYPOINT and CMD. I am going to design some
tests to illustrate the differences further more. The things to remember are:
1)
In the “docker run” command, things after the image
name replaces CMD
2)
ENTRYPOINT has two forms:
ENTRYPOINT
[“executable”, “param1”,”param2”] (exec
form, preferred)
ENTRYPOINT
command param1 param2 (shell
form)
With shell form, the process with PID 1 is the shell. When you send a killing signal to a container, PID 1 process receives the signal. If PID 1 is shell, you need to take care of handling killing signals.
My docker version is:
ubuntu@exp1:~$ docker version
Client:
Version:
17.03.0-ce
API
version: 1.26
Go
version: go1.7.5
Git
commit: 3a232c8
Built:
Tue Feb 28 08:01:32 2017
OS/Arch:
linux/amd64
Dockerfile_1
FROM openjdk:8
ENTRYPOINT ["java"]
CMD ["-version"]
Build and run Dockerfile_1
sudo docker build -t
test1 -f Dockerfile_1 .
sudo docker run -it
--name test1 --rm test1
This runs “java version”
sudo docker run -it
--name test1 --rm test1 aaa
(--rm deletes the container after it has finished running)
This runs “java aaa”. Things behind the image name replaces
CMD in the Dockerfile. Since there is no class aaa, this will throw out an
error: Error: Could not find or load
main class aaa
sudo docker run -it
--name test1 --rm --entrypoint
"echo" test1 aaa
This runs “echo aaa”. --entrypoint
runtime argument replace ENTRYPOINT
in the Dockerfile, note the arguments to --entrypoint
is placed at the end.
Dockerfile_2
FROM openjdk:8
ENTRYPOINT ["java aaa"]
CMD ["-version"]
Build and run Dockerfile_2
sudo docker build -t
test2 -f Dockerfile_2 .
sudo docker run -it
--name test2 --rm test2
This runs into an error: Error
response from daemon: oci runtime error: container_linux.go:247: starting container
process caused "exec: \"java aaa\": executable file not found in
$PATH".
This is because “java aaa” is treated as one executable.
This is because “java aaa” is treated as one executable.
Dockerfile_3
FROM openjdk:8
ENTRYPOINT ["/bin/sh",
"-c", "echo apple && java"]
CMD ["-version"]
Build and run Dockerfile_3
sudo docker run -it
--name test3 --rm test3
This runs "echo apple && java" not "echo apple && java -version", it is impossible to append additional arguments to “/bin/sh -c”.
Dockerfile_4
FROM openjdk:8
CMD ["java", "-version"]
Build and run Dockerfile_4
sudo docker build -t
test4 -f Dockerfile_4 .
sudo docker run -it
--name test4 --rm test4
This run "java -version".
sudo docker run -it
--name test4 --rm test4 aaa
This run “aaa”, and throws an error: docker: Error response from daemon: oci runtime error: container_linux.go:247: starting container process caused "exec: \"aaa\": executable file not found in $PATH".
This is because things after the image name replaces CMD, so 'java -version' is not run, "aaa" is run instead.
sudo docker run -it
--name test4 --rm test4 /bin/sh
"/bin/sh" replaces CMD, which enables you to get
inside the container.
Dockerfile_5
FROM openjdk:8
ENTRYPOINT ["java"]
Build and run Dockerfile_5
sudo docker build -t test5 -f Dockerfile_5 .
sudo docker run --rm --name test5 test5 aaa
This runs “java aaa”. Since there is no class aaa, this will
throw out an error: Error: Could not
find or load main class aaa.
This behavior is exactly the same as Dockerfile_1, even though there is no CMD defined in the Dockefile.
Dockerfile_6
FROM openjdk:8
RUN touch /tmp.txt
ENTRYPOINT tail -f /tmp.txt
Build and run Dockerfile_6
sudo docker build -t test6 -f Dockerfile_6 .
sudo docker run -d --name test6 test6
(-d runs container in the background)
$ sudo
docker exec test6 ps auxf
USER PID %CPU %MEM VSZ
RSS TTY STAT START TIME COMMAND
root 1 0.8 0.0
4288 724 ? Ss
09:34 0:00 /bin/sh -c tail -f
/tmp.txt
root 6
0.0 0.0 5980
756 ? S
09:34 0:00 tail -f /tmp.txt
docker exec
needs the container to be alive, “tail -f”
makes sure the container is alive.
Note the PID 1 process is shell.
$ sudo
docker inspect test6
"Path":
"/bin/sh",
"Args":
[
"-c",
"tail -f /tmp.txt"
]
Dockerfile_7
FROM
openjdk:8
RUN touch
/tmp.txt
ENTRYPOINT
["tail", "-f", "/tmp.txt"]
Note, you
can’t write
ENTRYPOINT ["tail", "-f /tmp.txt"], upon running the
image, you will receive an error: tail: invalid option -- ' '
Build and run Dockerfile_7
sudo docker build -t
test7 -f Dockerfile_7 .
sudo docker run -d --name test7 test7
$ sudo
docker exec test7 ps auxf
USER PID %CPU %MEM VSZ
RSS TTY STAT START TIME COMMAND
root 1 1.2 0.0
5980 708 ? Ss
09:43 0:00 tail -f /tmp.txt
Note the PID 1 process is tail.
In my tests, running both test6 and test7 in the foreground
(without -d), ctrl+c to kill them doesn’t work. I had expected to see it work
on test7, because in test7, PID 1 is tail, but it didn’t. This may have
something to do with https://www.weave.works/blog/my-container-wont-stop-on-ctrl-c-and-other-minor-tragedies/.