SIGTERM not working against child process spawned by entrypoint

35 Views Asked by At

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.

0

There are 0 best solutions below