我正在尝试在 Docker 上编写一个包装器,以合理的方式传播信号和标准输出。首先,Docker 不能很好地处理 SIGPIPE:
$ docker run --rm ubuntu yes | head
y
y
y
y
y
y
y
y
y
y
write /dev/stdout: broken pipe
$
额外的输出“write /dev/stdout:损坏的管道”即使有点烦人也没关系,但 Docker 化的进程不会停止。我编写了一个包装器来将 FIFO 安装为卷并重定向命令的标准输出:
fifo=`basename $0`.$$
mkfifo $fifo
cat $fifo &
docker run --rm -v$PWD/$fifo:$PWD/$fifo ubuntu sh -c "$* >$PWD/$fifo"
rm $fifo
这实现了我希望的标准输出;但是,现在 ctrl-C 不会停止容器。显然 shell 不会向前台子进程发送 SIGINT。我预计以下内容可以解决这个最新问题:
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
但是,在 ctrl-C 上,脚本退出,Dockerized 进程(和 cat)继续在我的终端上喷射输出。
我想做什么清楚吗?我是 UNIX 工作流程的忠实粉丝,但许多现代项目都依赖于 Docker(做操作系统应该已经做的事情)。更具体地说,我正在尝试对一些使用共享资源的 Docker 应用程序进行基准测试。我想在一个实例输出一定数量的行后终止它,并通过发送 SIGTERM 终止所有其他实例。
一种解决方案是在陷阱处理程序中杀死 cat 后台子进程而不是 Docker 后台子进程。最终,Docker 进程收到一个 SIGPIPE,该信号由于 FIFO 卷而起作用。
我猜测 Docker 守护进程不会将 SIGTERM 传播到此脚本中的底层进程。
必须有一些更干净的东西......
另一个解决方案是使用 docker run 的 --detach 选项,然后 docker stop 陷阱处理程序中的容器。
fifo=`basename $0`.$$
trap 'rm -f $fifo && docker stop $docker' INT TERM
mkfifo $fifo
docker=`docker run --detach --rm -v$PWD/$fifo:$PWD/$fifo ubuntu sh -c "$* >$PWD/$fifo"`
cat $fifo
rm $fifo
可以用
docker kill --signal=PIPE
解决方案替代 FIFO 卷吗?