info
Great article on this at https://www.ctl.io/developers/blog/post/dockerfile-entrypoint-vs-cmd/
Both instructions allow you to execute a command from within a container, but there is a subtle difference between executing commands via a shell or through exec.
Consider the following script
FROM ubuntu:trusty #shell mode CMD ping localhost
Build it with docker built -t demo .
Then we execute docker run -t demo
Now run docker ps - notice the command that was executed was "/bin/sh -c 'ping localhost'"
Let's change the script to
FROM ubuntu:trusty #exec mode CMD ["ping", "localhost"]
Build it with docker built -t demo .
Then we execute docker run -t demo
Now run docker ps - notice the command that was executed was "ping localhost"
Shell or exec mode
Shell mode
If you docker exec into the container that has been written CMD in shell mode, then list the processes you see something quite interesting (On Windows we don't actually see the expected result). If you straight after the docker run demo, you execute docker exec demo ps -f, you should get a list of all active processes. You will notice that the shell is PID 1. This can be problematic if we need to send any sort of POSIX signals to the container since /bin/sh won't forward signals to child processes (for a detailed write-up, see Gracefully Stopping Docker Containers).
Beyond the PID 1 issue, you may also run into problems with the shell form if you're building a minimal image which doesn't even include a shell binary. When Docker is constructing the command to be run it doesn't check to see if the shell is available inside the container -- if you don't have /bin/sh in your image, the container will simply fail to start.
A better option is to use the exec form of the ENTRYPOINT/CMD instructions which looks like this:
CMD ["executable","param1","param2"]
or
ENTRYPOINT ["executable","param1","param2"]