I’m trying to write a wrapper over Docker to propagate signals and standard output in a sensible way. First, Docker doesn’t handle SIGPIPE nicely:
$ docker run --rm ubuntu yes | head
y
y
y
y
y
y
y
y
y
y
write /dev/stdout: broken pipe
$
The extra output "write /dev/stdout: broken pipe" would be fine even if a little annoying, but the Dockerized process isn’t stopped. I wrote a wrapper to mount a FIFO as a volume and redirect the command’s standard output:
fifo=`basename $0`.$$
mkfifo $fifo
cat $fifo &
docker run --rm -v$PWD/$fifo:$PWD/$fifo ubuntu sh -c "$* >$PWD/$fifo"
rm $fifo
This does what I’m hoping for standard output; however, now, ctrl-C won’t stop the container. Apparently the shell won’t send SIGINT to the foreground child. I expected the following to work around this latest issue:
trap 'kill $!' INT TERM
fifo=`basename $0`.$$
mkfifo $fifo
cat $fifo &
docker run --rm -v$PWD/$fifo:$PWD/$fifo ubuntu sh -c "$* >$PWD/$fifo" &
wait
rm $fifo
However, on ctrl-C, the script exits, with the Dockerized process (and cat) continuing to spray output on my terminal.
Is it clear what I’m trying to do? I’m a big fan of UNIX workflow, but a lot of modern projects are depending on Docker (to do what the OS should already be doing). More specifically, I’m trying to benchmark a few Docker applications that are using a shared resource. I’d like to terminate one instance once it has output a certain number of lines and terminate all the other instances by sending SIGTERM.
2
Answers
One solution is to kill the cat background child rather than the Docker background child in the trap handler. Eventually, the Docker process gets a SIGPIPE, which works because of the FIFO volume.
I'm guessing somehow the Docker daemon doesn't propagate SIGTERM to the underlying process in this script.
There's gotta be something cleaner...
Another solution is to use docker run‘s –detach option and then docker stop the container in the trap handler.
Could the FIFO volume be replaced with a
docker kill --signal=PIPE
solution?