bash - 为什么要在 bash 中休眠和等待?

标签 bash docker

我无法理解 docker-compose.yml 中服务的启动命令. .yml 中的两个相关行是:

command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"

entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"

为什么要将sleep命令发送到后台然后等待呢?为什么不直接 sleep 6h 呢?另外,双美元符号是否只是转义了 ${!} 中的美元符号?

我正在寻找其他结合使用 sleep 和等待的地方,但似乎没有任何解释原因:

  1. http://www.masteringunixshell.net/qa17/bash-how-to-wait-seconds.html
  2. https://stackoverflow.com/a/13301329/828584
  3. https://superuser.com/a/753984/98583

最佳答案

当人们想要及时处理信号时,在后台休眠然后等待是有意义的。

When bash is executing an external command in the foreground, it does not handle any signals received until the foreground process terminates

(详细解释here)。

虽然第二个示例实现了一个信号处理程序,但对于第一个示例, sleep 是否在前台执行都没有区别。没有陷阱并且信号不会传播到 nginx 进程。 为了让它响应 SIGTERM 信号,入口点应该是这样的:

/bin/sh -c 'nginx -g \"daemon off;\" & trap exit TERM; while :; do sleep 6h  & wait $${!}; nginx -s reload; done'

测试它:

docker run --name test --rm --entrypoint="/bin/sh" nginx  -c 'nginx -g "daemon off;" & trap exit TERM; while :; do sleep 20 & wait ${!}; echo running; done'

停止容器

docker stop test

或发送 TERM 信号(docker stop 发送 TERM 后跟 KILL 如果主进程执行不退出)

docker kill --signal=SIGTERM test

通过这样做,脚本会立即退出。现在,如果我们删除 wait ${!},则陷阱会在 sleep 结束时执行。所有这些都适用于第二个示例。

注意:在这两种情况下,目的是每 12 小时检查一次证书更新并每 6 小时重新加载一次配置,如 guide 中所述。 这两个命令做得很好。恕我直言,第一个示例中的额外等待只是开发人员的疏忽。

已编辑:

似乎上面的合理化是为了给出后台 sleep 背后的可能原因,可能会造成一些困惑。 (有一个相关的帖子Why use nginx with “daemon off” in background with docker?)。

虽然上面答案中建议的命令是对问题中的命令的改进,但它仍然存在缺陷,因为如链接帖子中所述,nginx 服务器应该是主进程,而不是一个 child 。这可以使用 exec 系统调用轻松实现。脚本变为:

'while :; do sleep 6h; nginx -s reload; done & exec nginx -g "daemon off;"'

(更多信息请参见 Docker best practices 中的将应用程序配置为 PID 1 部分)

恕我直言,这要好得多,因为不仅 nginx 受到监控,而且还处理信号。例如,配置重新加载(nginx -s reload)也可以手动完成,只需向 docker 容器发送 HUP 信号(参见 Controlling nginx )。

关于bash - 为什么要在 bash 中休眠和等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56981892/

相关文章:

ios - 如何在iOS项目中通过unix shell命令(或命令工具)修改 ".strings"文件?

java - 在 Spring Boot 自定义嵌入式 launch.script 中设置 SPRING_PROFILES_ACTIVE

linux - bash 输出无效选项

docker - 访问 docker 容器的 config.v2.json 文件(Windows 10 docker 桌面)

docker - 是否可以将单个 docker 主机用于多件事情

linux - 在 bash 函数名称末尾使用加号

docker - 如何将文件卷挂载到远程 docker 守护进程?

Docker swarm 获取部署状态

laravel - 为什么我的 Redis Docker 容器为 KEYS * 显示 "(empty array)",而我绝对确定它有缓存数据并且工作正常

linux - 如何与其他格式化选项(如剪切和管道)一起进行内联 shell 替换