Docker 运行脚本以捕获中断信号 [英] Docker Run Script to catch interruption signal

查看:28
本文介绍了Docker 运行脚本以捕获中断信号的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 docker-compose.yml 可以启动几个容器.其中之一使用 Dockerimage 文件来安装该容器中所需的所有内容.

我想添加一个脚本,每次等待中断信号 0、9 和 137 时都会运行.

现在,我正在尝试将脚本作为 Dockerimage 文件中的入口点运行,但似乎不起作用.

这是Dockerimage文件的内容:

RUN apt-get update &&[...]工作目录/应用程序"入口点 ["/bin/bash", "-c", "/application/scripts/cl.sh"]

我做错了吗?我是否需要使用以下命令重建容器?

docker-compose 构建

<小时>

这是bash脚本cl.sh的内容

#!/bin/bash回声你好你好你好你好"trap 'echo 以 137 信号退出."' 137 0 9

目前脚本的唯一目的是测试一切正常.

解决方案

是的,可以实现您想要的,但在提供相应的代码之前,我必须评论您的问题代码,其中包含一些问题:

  • trap 'echo "Exiting with a 137 signal."' 137 0 9 是不正确的,因为 137 不是有效的信号编号(例如参见 关于信号的维基百科文章.

    也许您刚刚遇到了 137,因为它是对应于 信号 9 的退出代码(假设 137 = 128 + 9,请参阅 bash 文档中的这个附录.)

  • 0 (EXIT) 和 9 (KILL) 是有效的信号编号,但实际上最好只捕获 2 (INT) 和 15 (TERM),如 这个 SE/Unix 答案.

    确实,虽然 INT 和 TERM 信号可用于优雅终止",但 KILL 信号意味着必须立即终止进程,正如 man trap 中所述:

    <块引用>

    为 SIGKILL 或 SIGSTOP 设置陷阱会产生未定义的结果.[…] 捕获 SIGKILL 或 SIGSTOP 在语法上被一些历史实现所接受,但它没有任何效果.便携式 POSIX 应用程序无法尝试捕获这些信号.

  • 在入口点脚本的末尾设置陷阱是一个糟糕的策略,因为它在这个地方没用.相反,我建议你定义一个清理函数(最后一条指令是 exit),然后在脚本的开头在这个函数上设置一个陷阱,然后运行你的(非终止)应用程序之后.

因此有以下概念验证:

<块引用>

Dockerfile

来自 debian:latest工作目录/应用程序复制入口点.bash ./入口点 ["/bin/bash", "./entrypoint.bash"]

<块引用>

入口点.bash

#!/bin/bash清理(​​) {echo "清理中..."出口}陷阱清理 INT TERM尽管 :;做echo "你好!${SECONDS} 秒过去了......"睡眠 1 秒完毕

要测试它,你只需要运行:

$ docker build -t test-trap .$ docker run -d --name=TEST-TRAP test-trap# 等待几秒钟$ docker stop 测试陷阱$ docker logs -f TEST-TRAP你好!0 秒过去了...你好!1秒过去了...你好!2秒过去了……你好!3秒过去了……打扫干净...

I've a docker-compose.yml which starts several containers. One of which uses a Dockerimage file to install everything needed in that container.

I'd like to add a script which runs each time waiting for the interruption signals 0, 9 and 137.

Now, I'm trying to run the script as an Entrypoint in the Dockerimage file, but doesn't seems to work.

This is the content of the Dockerimage file :

RUN apt-get update && [...]
WORKDIR "/application"
ENTRYPOINT ["/bin/bash", "-c", "/application/scripts/cl.sh"] 

Am I doing something wrong? Do I need to rebuild the containers with the following command?

docker-compose build


This is the content of the bash script cl.sh

#!/bin/bash

echo "HELLO HELLO HELLO HELLO"

trap 'echo "Exiting with a 137 signal."' 137 0 9

The only purpose of the script at the moment is testing everything work.

解决方案

Yes it is possible to achieve what you want, but before presenting the corresponding code I have to comment on your question's code which contained some issues:

  • The line trap 'echo "Exiting with a 137 signal."' 137 0 9 is incorrect because 137 is not a valid signal number (see for example the Wikipedia article on signals).

    Maybe you just encountered 137 as it is the exit code corresponding to the signal 9 (given that 137 = 128 + 9, see this appendix in the bash doc.)

  • 0 (EXIT) and 9 (KILL) are valid signal numbers, but in practice it is better to only trap 2 (INT) and 15 (TERM), as suggested in this SE/Unix answer.

    Indeed while the INT and TERM signals can be used for "graceful termination", the KILL signal means the process must be killed immediately and as mentioned in man trap:

    Setting a trap for SIGKILL or SIGSTOP produces undefined results. […] Trapping SIGKILL or SIGSTOP is syntactically accepted by some historical implementations, but it has no effect. Portable POSIX applications cannot attempt to trap these signals.

  • Setting the trap at the end of the entrypoint script is a bad strategy, as it is useless in this place. Instead, I suggest that you define a cleanup function (the last instruction of which being exit), then set a trap on this function at the beginning of the script, and run your (non-terminating) application afterwards.

Hence the following proof-of-concept:

Dockerfile

FROM debian:latest
WORKDIR /app

COPY entrypoint.bash ./
ENTRYPOINT ["/bin/bash", "./entrypoint.bash"]

entrypoint.bash

#!/bin/bash

cleanup() {
    echo "Cleaning up..."
    exit
}

trap cleanup INT TERM

while :; do
    echo "Hello! ${SECONDS} secs elapsed..."
    sleep 1s
done

To test it, you just need to run:

$ docker build -t test-trap .
$ docker run -d --name=TEST-TRAP test-trap
  # wait a few seconds
$ docker stop TEST-TRAP
$ docker logs -f TEST-TRAP
Hello! 0 secs elapsed...
Hello! 1 secs elapsed...
Hello! 2 secs elapsed...
Hello! 3 secs elapsed...
Cleaning up...

这篇关于Docker 运行脚本以捕获中断信号的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆