set -e 和 exec "$@" 对 docker 入口点脚本有什么作用?

新手上路,请多包涵

我注意到 docker 的许多 entrypoint.sh 脚本都执行以下操作:

 #!/bin/bash
set -e

... code ...

exec "$@"

set -eexec "$@" 是干什么用的?

原文由 Nathan 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.2k
2 个回答

set -e 设置一个 shell 选项以在任何正在运行的命令以非零退出代码退出时立即退出。该脚本将返回失败命令的退出代码。从 bash 手册页:

设置-e:

如果管道(可能由单个简单命令组成)、列表或复合命令(参见上面的 SHELL GRAMMAR)以非零状态退出,则立即退出。如果失败的命令是紧跟在 while 或 until 关键字之后的命令列表的一部分、位于 if 或 elif 保留字之后的测试的一部分、在 && 或 || 中执行的任何命令的一部分,则 shell 不会退出列出除了最后一个 && 或 || 之后的命令,管道中除最后一个以外的任何命令,或者命令的返回值是否用 ! 反转。如果子 shell 以外的复合命令由于在忽略 -e 时命令失败而返回非零状态,则 shell 不会退出。如果设置了 ERR 陷阱,则会在 shell 退出之前执行。该选项分别适用于 shell 环境和每个子 shell 环境(参见上面的命令执行环境),并且可能导致子 shell 在执行子 shell 中的所有命令之前退出。

如果在忽略 -e 的上下文中执行复合命令或 shell 函数,则在复合命令或函数体中执行的任何命令都不会受到 -e 设置的影响,即使设置了 -e 并且命令返回故障状态。如果复合命令或 shell 函数在 -e 被忽略的上下文中执行时设置了 -e,则该设置在复合命令或包含函数调用的命令完成之前不会产生任何影响。


exec "$@" 通常用于使入口点通过,然后运行 docker 命令。它将用 "$@" 指向的命令替换当前运行的 shell。默认情况下,该变量指向命令行参数。

如果您有一个带有指向 entrypoint.sh 的入口点的映像,并且您将容器运行为 docker run my_image server start ,那将转换为在容器中运行 entrypoint.sh server start 。在 exec 行 entrypoint.sh ,以 pid 1 运行的 shell 将用命令 server start 替换自己。

这对于信号处理至关重要。如果不使用 exec ,上例中的 server start 将作为另一个 pid 运行,在它退出后,您将返回到您的 shell 脚本。对于 pid 1 中的 shell,默认情况下会忽略 SIGTERM。这意味着 docker stop 发送到您的容器的正常停止信号将永远不会被 server 进程接收。 10 秒后(默认情况下), docker stop 将放弃正常关闭并发送 SIGKILL 将强制您的应用退出,但可能会丢失数据或关闭网络连接,应用开发人员可能已经编码如果他们收到信号,就在附近。这也意味着您的容器总是需要 10 秒才能停止。

请注意,使用 shiftset -- 之类的 shell 命令,您可以更改 "$@" 的值。例如,这是一个脚本的一小部分,它从命令中删除 /bin/sh -c "..." 如果您对 CMD 使用 docker 的 shell 语法,则该命令会出现:

 # 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 "$@"

原文由 BMitch 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题