ENTRYPOINT and CMD

CMD vs ENTRYPOINT

CMD:

CMD ["/bin/ping", "-c", "3", "localhost"]
  • Easy to override: use for general purpose images

ENTRYPOINT:

CMD ["/bin/ping", "-c", "3", "localhost"]
  • Not made to be overridden: use for specific applications

CMD and ENTRYPOINT:

ENTRYPOINT ["/bin/ping", "-c", "3"]
CMD ["localhost"]
  • CMD is appended to ENTRYPOINT

  • Specifies the executable with ENTRYPOINT and the arguments with CMD

  • The CMD arguments can be overridden by the user of your container

  • Always use the exec form when combining both

Shell vs. Exec

With the shell form, docker will invoke a shell and pass the specified commands to it:

CMD ping localhost

This will be executed as /bin/sh -c 'ping localhost' by docker.

Consequences of the shell form: - the process with PID 1 is the shell and not your application - POSIX signals will be sent to the shell and not forwarded to your application - the container needs to provide a shell at /bin/sh - variable expansion will happen as you would expect

With the exec form, docker executes your commands directly in the container, without starting a shell:

CMD ["/bin/ping", "localhost"]

Consequences of the exec form: - your process is the PID 1, receiving all signals - no shell needed in the container - your command is interpreted as is, and there is no variable expansion (since there is no shell)

Forward signals

If using the shell form or a startup script, we can handle signals correctly by using the exec gosu combo command while starting the application.

This is the official Dockerfile example using this technique:

#!/usr/bin/env bash
set -e

if [ "$1" = 'custom-app' ]; then
    # do something
    exec gosu custom-app "$@"
fi

exec "$@"