Docker kata: difference between RUN, ENTRYPOINT and CMD in Dockerfile

When writing dockefile we usually encounter 3 commands that have very close meaning and function. These are RUN, ENTRYPOINT and CMD.

RUN
creates new docker image layer, we use this directive usually to install new package for our image.

$ cat Dockerfile 
FROM fedora:31

RUN dnf install -y cowsay

CMD ["cowsay", "Hi there!"]
$ 

CMD
specifies parameters with which container is to be used. Can be overridden from host command line when starting the container. CMD is typically used to feed default parameters to ENTRYPOINT directive.
Our Dockerfile:

FROM fedora:31

RUN dnf install -y cowsay

CMD ["cowsay", "Hi there!"]

Now let's run the container with different arguments.

coil@coil:~/Desktop/docker_tests$ sudo docker run my_cowsay 
 ___________
< Hi there! >
 -----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ sudo docker run my_cowsay cowsay Wow!
 ______
< Wow! >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ sudo docker run my_cowsay Hi there
docker: Error response from daemon: OCI runtime create failed: container_linux.go:345: starting container process caused "exec: \"Hi\": executable file not found in $PATH": unknown.
ERRO[0001] error waiting for container: context canceled 
$ 

In the last case we didnt specify that we want to run cowsay program, we just passed the string. Since CMD arguments got overriden by the new argument, the container run resulted in an error. This issue can be fixed with ENTRYPOINT directive in the docker file.

ENTRYPOINT
is being used when you want to run your container as an application. ENTRYPOINT values cannot be overriden from host command line and are integral part of an image. Such commands run every time.

Dockerfile:

FROM fedora:31

RUN dnf install -y cowsay

ENTRYPOINT ["cowsay"]
CMD ["Hi there!"]
$ sudo docker run my_cowsay 
 ___________
< Hi there! >
 -----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
$ sudo docker run my_cowsay Wow!
 ______
< Wow! >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

Practical example:
running jupyter notebook from docker container.

Last lines of Dockerfile:

# start the jupyter notebook in server mode
ENTRYPOINT ["jupyter","notebook"]
CMD ["--ip=0.0.0.0","--port=8888","--no-browser","--allow-root", "--notebook-dir=/notebooks"]

The jupyter notebook starts with some default arguments. We can change these easily when starting the container and change for example the port on which the notebook is listening.