From 82f25e898b37afd88d223efdaac333c21fff0969 Mon Sep 17 00:00:00 2001 From: "Zak B. Elep" Date: Sat, 10 Aug 2019 11:59:48 +0800 Subject: [PATCH 1/2] perl: Document PID 1 signal handling behavior Describe how Perl behaves when being run as PID 1 under containers, particularly on receiving SIGTERM/SIGINT, showing example for explicit signal handling. Ref Perl/docker-perl#44 --- perl/content.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/perl/content.md b/perl/content.md index 35b1c95fe4e4..9b9c3d5fd1ed 100644 --- a/perl/content.md +++ b/perl/content.md @@ -32,6 +32,32 @@ For many simple, single file projects, you may find it inconvenient to write a c $ docker run -it --rm --name my-running-script -v "$PWD":/usr/src/myapp -w /usr/src/myapp %%IMAGE%%:5.20 perl your-daemon-or-script.pl ``` +## Signal handling behavior notice + +As Perl will run as PID 1 by default in containers (unless an [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) is set,) special care needs to be considered when expecting to send signals (particularly SIGINT or SIGTERM) to it. For example, running + +```console +$ docker run -it --name sleeping_beauty --rm %%IMAGE%%:5.20 perl -E 'sleep 300' +``` + +and doing on another terminal, + +```console +$ docker exec sleeping_beauty kill 1 +``` + +will *not* stop the perl running on the `sleeping_beauty` container (it will keep running until the `sleep 300` finishes.) To do so, one must set a signal handler like this: + +```console +$ docker run -it --name quick_nap --rm %%IMAGE%%:5.20 perl -E '$SIG{TERM} = sub { say "recv TERM" }; sleep 300' +``` + +so doing `docker exec quick_nap kill 1` (or the simpler `docker stop quick_nap`) will immediately stop the container, and print `recv TERM` in the other terminal. + +If your Perl program is expected to handle signals and fork child processes, it is encouraged to use an init-like program for ENTRYPOINT, such as [dumb-init](https://github.com/Yelp/dumb-init) or [tini](https://github.com/krallin/tini) (the latter is available since Docker 1.13 via the `docker run --init` flag.) + +See also [Signals in perlipc](https://perldoc.pl/perlipc#Signals) as well as [Perl/docker-perl#44](https://github.com/Perl/docker-perl/issues/44). + ## Example: Creating a reusable Carton image for Perl projects Suppose you have a project that uses [Carton](https://metacpan.org/pod/Carton) to manage Perl dependencies. You can create a `%%IMAGE%%:carton` image that makes use of the [ONBUILD](https://docs.docker.com/engine/reference/builder/#onbuild) instruction in its `Dockerfile`, like this: From 087e4117ef3c32ec32e18412f34a032a81ea38f7 Mon Sep 17 00:00:00 2001 From: "Zak B. Elep" Date: Fri, 16 Aug 2019 11:48:46 +0800 Subject: [PATCH 2/2] perl: Update signal handler example Make clear that the signal handler does not kill the perl process on its own, thanks @tianon for the suggestion! --- perl/content.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perl/content.md b/perl/content.md index 9b9c3d5fd1ed..bbaa6841c98b 100644 --- a/perl/content.md +++ b/perl/content.md @@ -49,10 +49,10 @@ $ docker exec sleeping_beauty kill 1 will *not* stop the perl running on the `sleeping_beauty` container (it will keep running until the `sleep 300` finishes.) To do so, one must set a signal handler like this: ```console -$ docker run -it --name quick_nap --rm %%IMAGE%%:5.20 perl -E '$SIG{TERM} = sub { say "recv TERM" }; sleep 300' +$ docker run -it --name quick_nap --rm %%IMAGE%%:5.20 perl -E '$SIG{TERM} = sub { $sig++; say "recv TERM" }; sleep 300; say "waking up" if $sig' ``` -so doing `docker exec quick_nap kill 1` (or the simpler `docker stop quick_nap`) will immediately stop the container, and print `recv TERM` in the other terminal. +so doing `docker exec quick_nap kill 1` (or the simpler `docker stop quick_nap`) will immediately stop the container, and print `recv TERM` in the other terminal. Note that the signal handler does not stop the perl process itself unless it calls a `die` or `exit`; in this case, perl will continue and print `waking up` *after* it receives the signal. If your Perl program is expected to handle signals and fork child processes, it is encouraged to use an init-like program for ENTRYPOINT, such as [dumb-init](https://github.com/Yelp/dumb-init) or [tini](https://github.com/krallin/tini) (the latter is available since Docker 1.13 via the `docker run --init` flag.)