I'm trying to run an entrypoint script where it spawns a couple child processes (services), and I want docker stop or docker restart to propagate the SIGTERM to the children. However I cannot seem to get this to work.
First, the entrypoint is launched in exec mode, so the Dockerfile statement is as follows
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
Second, the services launched by the entrypoint.sh is started via exec, so the parent child pid relationship should be preserved.
I've tried a couple different solutions to attempt to propagate the SIGTERM to no avail. Below is the entrypoint script I have so far.
#!/bin/bash
child_pids=()
apache2() {
source /etc/apache2/envvars
source /etc/default/apache-htcacheclean
exec /usr/sbin/apache2 -D NO_DETACH
}
naemon() {
exec sudo -u naemon /usr/bin/naemon /etc/naemon/naemon.cfg
}
pdagent() {
exec sudo -u pdagent /usr/share/pdagent/bin/pdagentd.py
}
postfix() {
if ! [ "${MAIL_RELAY_HOST}" = "" ]; then
sed -i "s/relayhost =.*/relayhost = ${MAIL_RELAY_HOST}/" /etc/postfix/main.cf
fi
if ! [ "${MAIL_INET_PROTOCOLS}" = "" ]; then
sed -i "s/inet_protocols =.*/inet_protocols = ${MAIL_INET_PROTOCOLS}/" /etc/postfix/main.cf
fi
sed -i "s/myhostname =.*/myhostname = $(hostname)/" /etc/postfix/main.cf
sed -i "s/mydestination =.*/mydestination = ${NAEMON_FQDN}, \$myhostname, localhost.localdomain, localhost/" /etc/postfix/main.cf
sed -i "/^myorigin =.*/d" /etc/postfix/main.cf
echo "${NAEMON_FQDN}" > /etc/mailname
#postfix runs in a chroot and needs resolv.conf to resolve hostnames
cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf
exec /usr/lib/postfix/sbin/master -d -c /etc/postfix
}
xinetd() {
exec /usr/sbin/xinetd -dontfork -pidfile /run/xinetd.pid
}
terminate_children() {
echo "Terminating child processes..."
for pid in "${child_pids[@]}"; do
kill -SIGTERM "$pid" 2>/dev/null
echo "Sent SIGTERM to PID $pid"
wait "$pid"
done
}
naemon &
child_pids+=("$!")
apache2 &
child_pids+=("$!")
pdagent &
child_pids+=("$!")
postfix &
child_pids+=("$!")
xinetd &
child_pids+=("$!")
echo ${child_pids[@]}
trap terminate_children SIGINT SIGTERM
wait
The script launches the child processes into the background, storing the pid into an array. It traps the SIGTERM, and runs the terminate_children() function, which uses kill to send the SIGTERM to the respective pids. However, when I issue the docker restart or docker stop, I can see that it shows that it sent the kill to Naemon's pid, and as it waits for the pid to exit, Docker reaches the timeout limit of 10s and forcefully kills everything. If I try to do docker stop --time -1 which disables the timeout, the command would wait forever, because the child process does not exit. I also tested manually exec into the container's bash, and issuing the same kill -SIGTERM <pid> works as expected and the child process terminates gracefully.
I also tried using tini. With it launched as the entrypoint process, and having it launch my entrypoint script, which I disabled the trap statement, if I issue a docker stop or docker restart, it flat out does not seem to react to the SIGTERM and immediately kills all associated processes.
What am I doing wrong here?
The child processes should exit gracefully.