Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does set -e and exec "$@" do for docker entrypoint scripts?

Tags:

shell

docker

It basically takes any command line arguments passed to entrypoint.sh and execs them as a command. The intention is basically "Do everything in this .sh script, then in the same shell run the command the user passes in on the command line".

See:

  • What are the special dollar sign shell variables?
  • Need explanations for Linux bash builtin exec command behavior

set -e sets a shell option to immediately exit if any command being run exits with a non-zero exit code. The script will return with the exit code of the failing command. From the bash man page:

set -e:

Exit immediately if a pipeline (which may consist of a single simple command), a list, or a compound command (see SHELL GRAMMAR above), exits with a non-zero status. The shell does not exit if the command that fails is part of the command list immediately following a while or until keyword, part of the test following the if or elif reserved words, part of any command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted with !. If a compound command other than a subshell returns a non-zero status because a command failed while -e was being ignored, the shell does not exit. A trap on ERR, if set, is executed before the shell exits. This option applies to the shell environment and each subshell environment separately (see COMMAND EXECUTION ENVIRONMENT above), and may cause subshells to exit before executing all the commands in the subshell.

If a compound command or shell function executes in a context where -e is being ignored, none of the commands executed within the compound command or function body will be affected by the -e setting, even if -e is set and a command returns a failure status. If a compound command or shell function sets -e while executing in a context where -e is ignored, that setting will not have any effect until the compound command or the command containing the function call completes.


exec "$@" is typically used to make the entrypoint a pass through that then runs the docker command. It will replace the current running shell with the command that "$@" is pointing to. By default, that variable points to the command line arguments.

If you have an image with an entrypoint pointing to entrypoint.sh, and you run your container as docker run my_image server start, that will translate to running entrypoint.sh server start in the container. At the exec line entrypoint.sh, the shell running as pid 1 will replace itself with the command server start.

This is critical for signal handling. Without using exec, the server start in the above example would run as another pid, and after it exits, you would return to your shell script. With a shell in pid 1, a SIGTERM will be ignored by default. That means the graceful stop signal that docker stop sends to your container, would never be received by the server process. After 10 seconds (by default), docker stop would give up on the graceful shutdown and send a SIGKILL that will force your app to exit, but with potential data loss or closed network connections, that app developers could have coded around if they received the signal. It also means your container will always take the 10 seconds to stop.

Note that with shell commands like shift and set --, you can change the value of "$@". E.g. here's a short part of a script that removes the /bin/sh -c "..." from the command that can appear if you use docker's shell syntax for CMD:

# convert `/bin/sh -c "server start"` to `server start`
if [ $# -gt 1 ] && [ x"$1" = x"/bin/sh" ] && [ x"$2" = x"-c" ]; then
  shift 2
  eval "set -- $1"
fi

....

exec "$@"

set -e - exit script if any command fails (non-zero value)

exec "$@" - will redirect input variables, see more here