exec as a pipeline component

182 Views Asked by At

For our application running inside a container it is preferable that it receives a SIGTERM when the container is being (gracefully) shutdown. At the same time, we want it's output to go to a log file.

In the startscript of our docker container, we had therefore been using bash's exec similar to this

exec command someParam >> stdout.log

That worked just fine, command replaced the shell that had been the container's root process and would receive the SIGTERM.

Since the application tends to log a lot, we decided to add log rotation by using Apache's rotatelogs tool, i.e.

exec command | rotatelogs -n 10 stdout.log 10M

Alas, it seems that by using the pipe, exec can no longer have command replace the shell. When looking at the processes in the running container with pstree -p, it now looks like this

mycontainer@/#pstree -p
start.sh(1)-+-command(118)
            `-rotatelogs(119)

So bash remains the root process, and does not pass the SIGTERM on to command. Before stumbling upon exec, I had found an approach that installs a signal handler into the bash script, which would then itself send a SIGTERM to the command process using kill. However, this became really convoluted, getting the PID was also not always straightforward, and I would like to preserve the convenience of exec when it comes to signal handling and get piping for log rotation. Any idea how to accomplish this?

2

There are 2 best solutions below

1
glenn jackman On

Perhaps you want

exec sh -c 'command | rotatelogs -n 10 stdout.log 10M'
0
rodvlopes On

I was able to get around this by using process substitution. For your specific case the following may work.

exec command > >(rotatelogs -n 10 stdout.log 10M)

To reproduce the scenario I built this simple Dockerfile

FROM perl
SHELL ["/bin/bash", "-c"]

# The following will gracefully terminate upon docker stop
CMD exec perl -e '$SIG{TERM} = sub { $|++; print "Caught a sigterm!\n"; sleep(5); die "is the end!" }; sleep(30);' 2>&1 > >(tee /my_log)

# The following won't gracefully terminate upon docker stop
#CMD exec perl -e '$SIG{TERM} = sub { $|++; print "Caught a sigterm!\n"; sleep(5); die "is the end!" }; sleep(30);' 2>&1 | tee /my_log

Build docker build -f Dockerfile.meu -t test .

Run docker run --name test --rm -ti test

Stop it docker stop test

Output:

Caught a sigterm!
is the end! at -e line 1.