Docker bash shell 脚本无法捕获 SIGINT 或 SIGTERM

the*_*can 15 bash shell sigint sigterm docker

我的目录中有以下两个文件:

Dockerfile

FROM debian

WORKDIR /app
COPY start.sh /app/

CMD ["/app/start.sh"]
Run Code Online (Sandbox Code Playgroud)

start.sh(使用权限 755 chmod +x start.sh

FROM debian

WORKDIR /app
COPY start.sh /app/

CMD ["/app/start.sh"]
Run Code Online (Sandbox Code Playgroud)

然后我运行以下命令:

$ docker build . -t tmp
$ docker run --name tmp tmp
Run Code Online (Sandbox Code Playgroud)

然后我期望按 Ctrl+C 会向程序发送 SIGINT,该程序会将 SIGINT 打印到屏幕然后退出,但这并没有发生。

我还尝试运行$ docker stop tmp,我希望它会向程序发送一个 SIGTERM ,但$ docker logs tmp之后检查显示 SIGTERM 未被捕获。

为什么 bash 脚本没有捕获 SIGINT 和 SIGTERM?

Eri*_*kMD 6

实际上,只要您使用以下命令之一运行容器,您Dockerfilestart.sh入口点脚本就可以像我一样工作:Ctrl+C

  • docker run --name tmp -it tmp
  • docker run --rm -it tmp

文档详细信息

如指定docker run --help

  • --interactive= CLI标志-i要求保持 STDIN 打开,即使未附加
    (通常对于交互式 shell 很有用,或者也传递--detach= -dCLI 标志时)
  • --tty= CLI标志-t要求分配一个伪 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问题以了解详细信息:加速docker-compose shutdown }


Lui*_*ñoz 0

CTRL+C 发送信号以docker在该控制台上运行。
要向脚本发送信号,您可以使用

docker exec -it <containerId> /bin/sh -c "pkill -INT -f 'start\.sh'"
Run Code Online (Sandbox Code Playgroud)

或者包含echo "my PID: $$"在您的脚本中并发送

docker exec -it <containerId> /bin/sh -c "kill -INT <script pid>"
Run Code Online (Sandbox Code Playgroud)

docker 中的某些 shell 实现可能会忽略该信号。该脚本将正确响应pkill -15。请注意,指定的信号没有SIG前缀

#!/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
Run Code Online (Sandbox Code Playgroud)

sleep命令被短命令的无限循环所取代,因为sleep 可能会忽略一些信号