我无法理解 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 和等待的地方,但似乎没有任何解释原因:
最佳答案
当人们想要及时处理信号时,在后台休眠然后等待是有意义的。
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/