Anthony Kong
Anthony Kong

Reputation: 40754

Unable to trap TERM signal from 'docker stop'

This is my bash script used in CMD

#!/bin/bash
set -eo pipefail

echo "Setting trap"
echo $$
echo $BASHPID
trap 'cleanup' TERM
trap 'cleanup' KILL

cleanup() {
    echo "Cleaning up..."
    kill -TERM `jobs -p`
}


# To start the essential services
service ntp start
service awslogs start

cd /app
python -m job_manager  &

wait

The Docker file is not very interesting

FROM ubuntu:16.04

RUN apt-get update --fix-missing && apt-get install -y \
  git \
  python \
  python-pip \
  ntp \
  curl

ENV APP_HOME /app
RUN mkdir -p ${APP_HOME}
COPY src/ ${APP_HOME}/

# job-cmd.sh is kept here    
COPY docker/helper-files/* /   

CMD /job-cmd.sh

The idea is trap the TERM signal inside job-cmd.sh and then pass on to the python task.

I have tried a number of time and it did not work. After I add these call

echo $$
echo $BASHPID

I realised the pid of the CMD process is actually 7 instead of 1 as I would expect.

My questions:

1) Why the bash process is assigned PID 7?

2) How can I fix the my job script/dockerfile?

Upvotes: 2

Views: 2101

Answers (2)

Venkateswara Rao
Venkateswara Rao

Reputation: 5392

You could use trap command in the bash to do this.

#!/bin/bash
#

function gracefulShutdown {
  echo "Shutting down!"
  # do something..
}
trap gracefulShutdown SIGTERM TERM INT

./subprocess.sh &

tail --pid=${!} -f /dev/null &
wait "${!}"

tail command just waits for subprocess to complete, while wait command waits for the tail to complete... Now, main process is the one which is waiting on.. so any docker signals directly reach the trap we set above...

Example is available at: https://github.com/iamdvr/docker-trap-subprocess

enter image description here

Upvotes: 0

Andrii L.
Andrii L.

Reputation: 141

I think this is happening because you are using the shell form of the CMD instruction. From https://docs.docker.com/engine/reference/builder/#cmd:

If you want to run your command without a shell then you must express the command as a JSON array and give the full path to the executable. This array form is the preferred format of CMD.

So, replace your CMD instruction in Dockerfile with:

CMD ["/job-cmd.sh"]

Then your Bash process will be assigned PID 1. Your TERM handler will work, but you can't trap the KILL signal. From man trap:

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.

FYI, I explained more about the PID 1 problem here: https://serverfault.com/questions/869543/bash-script-entrypoint-pid-1-kills-tail-sub-process-only-if-a-fake-trap-whi/870872#870872

Upvotes: 4

Related Questions