Catching Signals inside Docker


#1

Hi!

We need to catch the SIGTERM signal to gracefully stop our app when the device is rebooted from the resin console or an update arrives.

Here is what we have:

Our dockerfile ends like this:

CMD ["/app/start.sh"]

Then on start.sh we do the things needed before the x server starts, and on the end of start.sh we do:

while :;do
** rm /tmp/.X0-lock || true**
** FRAMEBUFFER=/dev/fb1 startx /bin/bash /app/start2.sh**
done

that runs our start2.sh script, which runs after the x server is up, there we start our electron app, and there is a small software watchdog.

/app/node_modules/electron/dist/electron /app/main.js --enable-logging &

while [ -f /app/ramdisk/watchdog ]
do
** rm -rf /app/ramdisk/watchdog**
** sleep 10**
done

We need to catch the signal in the electron app, or in any bash script, but we have tried on the 3 places, start.sh/start2.sh/electron app and somehow the signal is not reaching any.

top says the process id 1 is entry.sh (which is from resin).

I would appreciate any help!

Thank you in advance!!!


#2

Hey @diegosucaria ,

TL;DR Here is a demo project of mine --> https://github.com/shaunmulligan/lifecycle

The answer to this depends on a couple of things. Namely,

  1. What base image you have: FROM resin/raspberrypi3-python:latest , etc.
  2. whether or not you have systemd enabled in your container via ENV INITSYSTEM=on
  3. What version of resinOS and supervisor version your device is running.

For 1. you should aim to have as new a possible base image, if you want to make sure you have the most current latest, you need to rebuild your whole container. That can be done using git push resin master:resin-nocache

For 2. if you have ENV INITSYSTEM=on in your dockerfile, systemd will be running in your container and manage the child processes, making sure SIGTERM gets propagated to all of them. One thing to note here is that you need to be running a relatively new version of resinOS (something above v1.12 should be good) because the way docker sends stop signals was fixed in that version.

Also not that if you are launching code from a bash script you need to trap the SIGTERM in your bash script and propagate it on to the child process that bash script has started. I think if you have INITSYSTEM=on then systemd will do all of this for you.

Hope this helps out.


#3

Hi @shaunmulligan!

#1 We are using resin/raspberrypi3-node:6-20170202

#2 We are not using systemd, since I can’t finde ENV INITSYSTEM=on in the dockerfile.

#3 Resin OS 1.24.1, Supervisor 2.8.3

Yes, we currently have traps in the bash script:

_term() {
echo "Caught SIGTERM signal!"
echo “KILLED” > /data/appkilled
}
trap _term SIGTERM

On both of them.

So, the signals are not propagating because we are not using systemd?

Thank you!


#4

I think you may need to update your base image, some additional signal handling things were added in recently and there is another update which will land later next week which will fix things further if you look here: https://github.com/resin-io-library/base-images/pull/237

For #2 you can just add that to your dockerfile, or even add it in the “Environment Variables” on the dashboard and it will enable systemd.

I have updated my example code to demonstrate the use with bash. It should work with or without INITSYSTEM=on, however very occasionally the signal is not trapped (not sure why), so I think the PR mentioned above will fix this issue. With INITSYSTEM=on it is never missed.


#5

it’s working!

After adding INITSYSTEM=on the trap on start.sh got the signal!!!

Thank you!

Edit: the only problem now is that all processes are getting the sigterm signal and my x server is getting killed first, not allowing me to set an image before