I have a post Shell Arguments Format talked about exec "$@" (当时并没有在意为什么在docker中这么使用), the script docker-entrypoint.sh is a very common and flexible way to accept different parameters when start docker container and run application as PID 1, this allows the application to receive any Unix signals sent to the container (之前遇到过这个问题, 非PID 1的进程在对container 的终止signal 没有反应).
# shell parameter expansion # if LOGLEVEL is null or unset, then assign null to it # env variable can set from `-e` with docker run loglevel="${LOGLEVEL:-}"
# if the first argument looks like a parameter (i.e. start with '-'), run Envoy # ${1#-} 的意思是对于第一个positional parameter, 是不是以-开头 # ${1#-} expand 的结果是去掉最短的match部分 if [ "${1#-}" != "$1" ]; then # re-set $@ value # see below explanation set -- envoy "$@" fi
# have CMD ['envoy'] in dockerfile # this is the default parameter to entrypoint if [ "$1" = 'envoy' ]; then # set the log level if the $loglevel variable is set if [ -n "$loglevel" ]; then # 更新位置参数 set -- "$@" --log-level "$loglevel" fi fi
# ENVOY_UID is the environment variables you specified # to set envoy userid/group if [ "$ENVOY_UID" != "0" ]; then if [ -n "$ENVOY_UID" ]; then usermod -u "$ENVOY_UID" envoy fi if [ -n "$ENVOY_GID" ]; then groupmod -g "$ENVOY_GID" envoy fi # Ensure the envoy user is able to write to container logs chown envoy:envoy /dev/stdout /dev/stderr
# su-exec switch user exec # https://github.com/ncopa/su-exec su-exec envoy "${@}" else # becomes PID 1 # 注意有double quote exec"${@}" fi
For example:
1 2 3 4 5 6 7 8
# start as bash docker run --rm -it envoy_image_name:tag bash
# pass parameters `--help` and run docker run --rm -it envoy_image_name:tag --help
# run as default CMD `envoy` with ENTRYPOINT docker run --rm -it -e ENVOY_UID=1001 -e LOGLEVEL="info" envoy_image_name:tag
The set -- command sets the positional parameters and link new tokens with existing position parameters, The -- is the standard “don’t treat anything following this as an option”,也就是说这是要排列位置参数了,而不是重置位置参数:
1 2 3 4 5 6 7 8
set a b c # output "a b c" echo$1$2$3
# 相当于$@ = newToken "$@" set -- newToken "$@" # it actually exec "newToken a b c" exec"${@}"
# if quiet log, then redirect to /dev/null # otherwise redirect to 1 (stdout) if [ -z "${NGINX_ENTRYPOINT_QUIET_LOGS:-}" ]; then # link file descriptor 3(additional) to 1 (stdout) # 3 is file descriptor see below explanation
# exec can preserve the setting exec 3>&1 else exec 3>/dev/null fi # why use new fd 3: 3 is used by echo later, easy to manage redirect to where
# -o: or if [ "$1" = "nginx" -o "$1" = "nginx-debug" ]; then if /usr/bin/find "/docker-entrypoint.d/" -mindepth 1 -maxdepth 1 -type f -print -quit 2>/dev/null | read v; then # redirect message from 1 (implicitly) to 3 (stdout in essence) # echo >&3 facilitate reading, see below explanation echo >&3 "$0: /docker-entrypoint.d/ is not empty, will attempt to perform configuration"
echo >&3 "$0: Looking for shell scripts in /docker-entrypoint.d/" find "/docker-entrypoint.d/" -follow -type f -print | sort -V | whileread -r f; do case"$f"in *.sh) # -x: file exists and executable if [ -x "$f" ]; then echo >&3 "$0: Launching $f"; "$f" else echo >&3 "$0: Ignoring $f, not executable"; fi ;; *) echo >&3 "$0: Ignoring $f";; esac done
echo >&3 "$0: Configuration complete; ready for start up" else echo >&3 "$0: No files found in /docker-entrypoint.d/, skipping configuration" fi fi