在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
?另外,双美元符号是否只是在${!}
中逃脱了美元符号?
我正在寻找将睡眠和等待结合在一起使用的其他地方,但是似乎没有一个关于原因的解释:
答案 0 :(得分:5)
已编辑
:当人们想及时处理信号时,有必要在后台休眠然后等待。
当bash在前台执行外部命令时,它会执行 在前台进程处理之前,不处理任何收到的信号 终止
(详细说明here)。
尽管第二个示例实现了一个信号处理程序,但对于第一个示例,无论是否在前台执行睡眠都没有区别。没有陷阱,信号也不会传播到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中所述 这两个命令就可以了。恕我直言,第一个示例中的额外等待只是开发人员的疏忽。
答案 1 :(得分:3)
我看到的唯一原因:
如果您killall -INT sleep
,这不会影响主脚本。
尝试一下:
while true ;do sleep 12; echo yes;done
然后发送 Interrupt
信号:
killall -INT sleep
这会中断工作!
立即尝试
while true ;do sleep 12 & wait $! ; echo yes;done
然后再次:
killall -INT sleep
工作不会中断!
采样输出,从另一个窗口中击中killall -INT sleep
:
user@myhost:~$ while true ;do sleep 12; echo yes;done
break
user@myhost:~$ while true ;do sleep 12 & wait $! ; echo yes;done
[1] 30632
[1]+ Interrupt sleep 12
yes
[1] 30636
[1]+ Interrupt sleep 12
yes
[1] 30638
[1]+ Interrupt sleep 12
yes
[1] 30640