【问题标题】:What does set -e and exec "$@" do for docker entrypoint scripts?set -e 和 exec "$@" 对 docker 入口点脚本有什么作用?
【发布时间】:2016-12-29 04:42:05
【问题描述】:

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

#!/bin/bash
set -e

... code ...

exec "$@"

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

【问题讨论】:

  • 参见BashFAQ #105 回复:为什么set -e 被认为比手写错误处理更容易出错。 (如果赶时间,请跳过顶部的类比进行下面的练习)。

标签: shell docker


【解决方案1】:

它基本上接受任何传递给entrypoint.sh 的命令行参数并将它们作为命令执行。其意图基本上是“在这个 .sh 脚本中执行所有操作,然后在同一个 shell 中运行用户在命令行中传递的命令”。

见:

【讨论】:

【解决方案2】:

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

设置-e:

如果管道(可能包含单个简单命令)、列表或复合命令(请参阅 SHELL GRAMMAR 以上),以非零状态退出。外壳不退出 如果失败的命令立即成为命令列表的一部分 在一段时间或直到关键字之后,if 之后的部分测试 或 elif 保留字,在 && 或 || 中执行的任何命令的一部分 列出除了最后的 && 或 || 之后的命令,任何 管道中的命令但最后一个,或者如果命令的返回值 正在与 ! 反转。如果子shell 以外的复合命令 返回非零状态,因为在执行 -e 时命令失败 忽略,shell 不会退出。执行 ERR 陷阱(如果设置) 在外壳退出之前。此选项适用于 shell 环境 和每个子shell环境分别(参见命令执行 上面的环境),并且可能导致子shell在执行之前退出 子shell中的所有命令。

如果复合命令或 shell 函数在上下文中执行 -e 被忽略,在复合命令或函数体中执行的任何命令都不会受到 -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 "$@"

【讨论】:

  • 参见the POSIX test spec,它标志着-a 已过时。 [ "$#" -gt 1 ] && [ "$1" = /bin/sh ] 是正确的替换(当只使用非过时的语法时,不需要x"$1"hackery)。
  • 另外,shift 2; set -- $1eval 解析字符串的方式完全不同。考虑/bin/sh -c 'printf "%s\n" "hello world" "goodbye world"',如果您想要一个具体的测试用例,请参阅Bash doesn't parse quotes when converting a string to arguments
  • @CharlesDuffy 感谢关于过时选项的提示,我相信我会再次犯这个错误,旧习惯很难改掉。对于eval,我相信我仍然希望它能够反映/bin/sh -c 在字符串上的行为,但如果我遗漏了什么,请告诉我。
【解决方案3】:

set -e - 如果任何命令失败则退出脚本(非零值)

exec "$@" - 将重定向输入变量,查看更多here

【讨论】:

  • “将重定向输入变量”?诶? exec 确实有执行重定向的使用模式,但这不是那种模式。
猜你喜欢
  • 2015-11-22
  • 1970-01-01
  • 2020-04-28
  • 1970-01-01
  • 2013-11-06
  • 2016-10-08
  • 2017-07-13
  • 2023-01-31
  • 2018-07-08
相关资源
最近更新 更多