Docker Run Script to catch interruption signal

2019-02-28 05:43发布

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.

1条回答
女痞
2楼-- · 2019-02-28 06:39

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...
查看更多
登录 后发表回答