RUN or CMD or ENTRYPOINT


One of the most confusing parts of a Dockerfile for me it has always been the part where we execute or initiate the application.

docker-1

In Summary

  • RUN executes command(s) in a new layer on top of the current image. Often used to install packages and dependencies.

  • CMD sets default command and/or parameters, can be overwritten from the command line when docker container runs.

  • ENTRYPOINT Allows you to configure a container to run as an executable.

Difference between RUN and CMD

Don’t confuse RUN and CMD. RUN runs a command; CMD does not execute/run anything at build time, only specifies the command for the image.

SHELL and EXEC forms

All three instructions can be specified in shell or exec form.

SHELL form

<instruction> <command>

Examples

RUN apt-get install python3
CMD echo "Hello world"
ENTRYPOINT echo "Hello world"

When executed it runs as /bin/sh -c <command> as a normal shell command. For example the following Dockerfile

ENV name Foo Bar
ENTRYPOINT echo "Hello, $name"

when container runs as docker run -it <image> will produce output

Hello, Foo Bar

EXEC form

Prefered for CMD and ENTRYPOINT

<instruction> ["executable", "param1", "param2", ...]

Examples

RUN ["apt-get", "install", "python3"]
CMD ["/bin/echo", "Hello world"]
ENTRYPOINT ["/bin/echo", "Hello world"]

When is executed in exec form it calls executable directly, and shell processing does not happen. For example, the following Dockerfile

ENV name Foo Bar
ENTRYPOINT ["/bin/echo", "Hello, $name"]

when the container runs as docker run -it <image> will produce output

Hello, $name

If you need to run bash or sh, use exec form with /bin/bash as executable.

For example, the following Dockerfile

ENV name Foo Bar
ENTRYPOINT ["/bin/bash", "-c", "echo Hello, $name"]

when the container runs as docker run -it <image> will produce output

Hello, Foo Bar

RUN


The preferred method to install packages and dependencies. Executes commands on top of the current layer and creates a new one. It is usual to have more than one RUN instruction in a Dockerifle.

RUN has two forms:

  • RUN command (shell form)
  • RUN ["executable","param1","param2"] (exec form)

Example

FROM alpine:3.10.1

RUN apk add --update /
    python3 /
    py-pip /
    curl

All the commands above run in a single layer

The default shell for the *shell form** is /bin/sh -c. If you need to use a different shell like /bin/bash use the exec form instead.

RUN ["/bin/bash", "-c", "echo hello"]

CMD


It allows you to set a default command, which will be executed only when you run a container without specifying a command.

CMD has three forms:

  • CMD ["executable","param1","param2"] (exec form, preferred)
  • CMD ["param1","param2"] (sets additional default parameters for ENTRYPOINT)
  • CMD command param1 param2 (shell form)

The second form sets default parameters that will be added after ENTRYPOINT parameters if container runs without command line arguments.

Example

FROM alpine:3.10.1

RUN apk add --update \
    python3 \
    py-pip \
    curl

CMD ["python3","--version"]

Let’s build and tag the Dockerfile

docker build . -t alpine:ex3

and run it

docker run alpine:ex3

the output is

Python 3.7.3

But if we run the container with a command:

docker run alpine:ex3 cat /etc/issue

the CMD is ignored and cat /etc/issue runs instead. Output:

Welcome to Alpine Linux 3.10
Kernel \r on an \m (\l)

ENTRYPOINT


Allows you to configure a container to run as a executable. ENTRYPOINT commands are not ignored when Docker container runs with command line parameters.

ENTRYPOINT has two forms.

  • ENTRYPOINT ["executable", "param1", "param2"] (exec form preferred)
  • ENTRYPOINT command param1 param2 (shell form)

Example Exec Form

Exec form of ENTRYPOINT allows us to set command and parameters and then use either form of CMD to set additional parameters. ENTRYPOINT arguments are always used while CMD arguments can be overwritten by command line arguments.

FROM alpine:3.10.1

RUN apk add --update /
    python3 /
    py-pip /
    curl

ENTRYPOINT ["echo"]
CMD ["from CMD"]

Let’s build and tag the Dockerfile

docker build . -t alpine:ex5

and run it:

docker run alpine:ex5

output:

from CMD

Now let’s run it adding a parameter

docker run alpine:ex5 from here

output:

from here

Shell form

Shell form of ENTRYPOINT ignores any CMD or docker run command line arguments.

CMD and ENTRYPOINT interaction table

The table below shows what command is executed for different ENTRYPOINT / CMD combinations

No ENTRYPOINT ENTRYPOINT exec_entry p1_entry ENTRYPOINT ["exec_entry" "p1_entry"]
No CMD - /bin/sh -c exec_entry p1_entry exec_entry p1_entry
CMD [“exec_cmd”, “p1_cmd”] exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry exec_cmd p1_cmd
CMD [“p1_cmd”, “p2_cmd”] p1_cmd p2_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry p1_cmd p2_cmd
CMD exec_cmd p1_cmd /bin/sh -c exec_cmd p1_cmd /bin/sh -c exec_entry p1_entry exec_entry p1_entry /bin/sh -c exec_cmd p1_cmd

Sources:

https://docs.docker.com/engine/reference/builder/#run

https://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/