为什么在 docker 后台使用带有“守护进程关闭”的 nginx?

aht*_*hio 6 bash nginx docker

这一切都从这篇关于在 docker 中设置 nginx 和 certbot 的文章开始。在手册的最后,作者使用以下命令为 nginx 进行了自动证书更新:

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

我不是唯一一个不理解这部分的人,所以有一个问题:Why do sleep & wait in bash?

得到的答案是原始命令并不完美,这是更正后的版本:

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

但在这个命令中我看到nginx -g \"daemon off;\" & 为什么我们首先将 nginx 放在前台然后将其放入后台?有什么影响?为什么不首先在后台启动 nginx?

另一个问题:据我了解,while与原始命令不同,该周期保留在 docker 的前台。但是如果nginx if后台,是否意味着它死了,docker不在乎?前台while仍在工作,没问题。

最后一个问题:为什么在这个命令中有时我们会看到$${!},有时会看到${!}. ${!}来自同一问题的示例:

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'
Run Code Online (Sandbox Code Playgroud)

我知道这是一个角色逃跑,但我不明白这种情况的规则。

b0g*_*usb 4

但在这个命令中我看到 nginx -g \"daemon off;\" & 为什么我们首先将 nginx 放在前台,然后将其放入后台?有什么影响?为什么不首先在后台启动 nginx?

原因主要是为了突出差异,并无任何暗示。该命令相当于:

"/bin/sh -c 'nginx; trap exit TERM; while :; do sleep 6h  & wait $${!}; nginx -s reload; done'
Run Code Online (Sandbox Code Playgroud)

另一个问题:据我了解,与原始命令不同,while 循环保留在 docker 的前台。但是如果nginx if后台,是否意味着它死了,docker不在乎?在前台仍在工作时,没问题。

该命令基本上创建三个进程:shell 进程 ( /bin/sh)sleep 6Hnginx服务器。第四个进程 ( nginx -s reload) 每 6 小时分叉一次。Docker 始终监视进程,PID 1在本例中是 shell ( /bin/sh)。如果外壳死亡,容器就会退出。如果nginx作为 shell 进程子进程的服务器死掉了,docker 确实不在乎。

“更正”的版本没有解决这些问题。它与原来的问题相同。SO 问题的答案仅强调除非您想及时处理信号,否则不需要sleep和。wait代表着:

"/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx ..."
Run Code Online (Sandbox Code Playgroud)

执行与以下完全相同的操作:

"/bin/sh -c 'while :; do sleep 6h; nginx ..."
Run Code Online (Sandbox Code Playgroud)

总之,正确的实现应该nginx是主进程 ( PID 1) 和在后台运行的另一个进程每 6 小时醒来一次,以通知服务器重新加载配置。原始命令和更正后的命令都没有正确实现所有这些。

要解决前面提到的问题,命令应如下所示:

'while :; do sleep 6h; nginx -s reload; done & exec nginx -g "daemon off;"'
Run Code Online (Sandbox Code Playgroud)

系统exec调用将 shell 进程的内容替换为服务器,nginx使nginx主进程处于前台。所有信号现在都正确传播到服务器(另请参阅控制 nginx)。

注意:这个解决方案仍然有一个缺陷。shell 进程(while 循环)不受监控。如果由于任何原因该进程退出,docker 唯一要做的就是发送警报。

希望这能带来一些启发。