首页 > 解决方案 > 为什么在docker的后台使用带有“守护进程关闭”的nginx?

问题描述

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

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

我不是唯一一个不理解这部分的人,所以有一个关于 SO 的问题:为什么要在 bash 中睡眠和等待?

给出的答案是原始命令并不完美,这里是更正的版本:

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

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

另一个问题:据我了解,while与原始命令不同,循环停留在 docker 的前台。但是如果nginx如果是后台,是不是就意味着如果死掉了,docker就不管了?在前台while仍然工作,没问题。

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

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'

我知道这是一个字符转义,但我不知道这种情况的规则。

标签: bashdockernginx

解决方案


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

原因主要是为了突出差异,没有任何影响。该命令等效于:

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

另一个问题:据我了解,与原始命令不同,while 循环停留在 docker 的前台。但是如果nginx如果是后台,是不是就意味着如果死掉了,docker就不管了?在前台仍然工作,没问题。

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

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

"/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx ..."

与以下内容完全相同:

"/bin/sh -c 'while :; do sleep 6h; nginx ..."

总之,一个正确的实现将nginx作为主进程(PID 1)和另一个在后台运行的进程每 6 小时唤醒一次,以向服务器发出重新加载配置的信号。原始命令和更正后的命令都不能正确实现所有这些。

要解决前面提到的问题,命令应该是这样的:

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

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

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

希望这能有所启发。


推荐阅读