如何解决Docker bash shell 脚本无法捕获 SIGINT 或 SIGTERM 文档详情相关说明
Dockerfile
FROM debian
workdir /app
copY start.sh /app/
CMD ["/app/start.sh"]
start.sh
(使用 chmod +x start.sh
的权限为 755)
#!/bin/bash
trap "echo SIGINT; exit" SIGINT
trap "echo SIGTERM; exit" SIGTERM
echo Starting script
sleep 100000
然后我运行以下命令:
$ docker build . -t tmp
$ docker run --name tmp tmp
然后我希望按 Ctrl+C 会向程序发送一个 SIGINT,该程序会将 SIGINT 打印到屏幕然后退出,但这不会发生。
我也尝试运行 $ docker stop tmp
,我希望它会向程序发送一个 SIGTERM,但检查 $ docker logs tmp
后显示未捕获 SIGTERM。
为什么 SIGINT 和 SIGTERM 没有被 bash 脚本捕获?
解决方法
CTRL+C 向在该控制台上运行的 docker
发送信号。
要向脚本发送信号,您可以使用
docker exec -it <containerId> /bin/sh -c "pkill -INT -f 'start\.sh'"
或者在您的脚本中包含 echo "my PID: $$"
并发送
docker exec -it <containerId> /bin/sh -c "kill -INT <script pid>"
docker 中的某些 shell 实现可能会忽略该信号。
此脚本将正确响应 pkill -15
。请注意,信号被指定为 without the SIG
prefix。
#!/bin/sh
trap "touch SIGINT.tmp; ls -l; exit" INT TERM
trap "echo 'really exiting'; exit" EXIT
echo Starting script
while true; do sleep 1; done
自 sleep
may ignore some signals 起,长 sleep
命令被短命令的无限循环所取代。
实际上,如果您使用以下命令之一运行容器,您的 Dockerfile
和 start.sh
入口点脚本与我使用 Ctrl+C 时一样: >
docker run --name tmp -it tmp
docker run --rm -it tmp
文档详情
如docker run --help
中所述:
-
--interactive
=-i
CLI 标志要求即使未附加也保持 STDIN 打开
(通常对交互式 shell 有用,或者当还传递--detach
=-d
CLI 标志时) -
--tty
=-t
CLI 标志要求分配一个伪 TTY
(特别是将信号转发到 shell 入口点,对您的用例特别有用)
相关说明
为了完整起见,请注意有几个相关问题可能使 docker stop
花费太多时间并“退回”到 docker kill
,这可能在 shell入口点启动其他一些进程:
- 首先,当 shell 入口点的最后一行运行另一个主程序时,不要忘记在这一行前面加上内置的
exec
:exec prog arg1 arg2 ...
- 但是当 shell 入口点打算长时间运行时,捕获信号(至少
INT
/TERM
,但 不是KILL
)是很重要;
{另见这个问题:Docker Run Script to catch interruption signal} - 否则,如果信号没有转发到子进程,我们就有可能遇到“PID 1 僵尸收割问题”,例如
{另请参阅此 SO 问题了解详情:Speed up docker-compose shutdown}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。