1

对于我们在容器内运行的应用程序,最好在容器(正常)关闭时接收 SIGTERM。同时,我们希望它的输出进入日志文件。

因此,在我们的 docker 容器的启动脚本中,我们一直在使用 bashexec与此类似

exec command someParam >> stdout.log

这工作得很好,command替换了作为容器根进程并接收 SIGTERM 的 shell。

由于应用程序倾向于记录大量日志,我们决定使用 Apache 的rotatelogs工具添加日志轮换,即

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

唉,似乎通过使用管道, exec 不能再command更换外壳了。用 来查看正在运行的容器中的进程时pstree -p,现在看起来像这样

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

所以 bash 仍然是根进程,并且不会将 SIGTERM 传递给命令。在偶然发现 exec 之前,我发现了一种将信号处理程序安装到 bash 脚本中的方法,然后它本身会command使用kill. 然而,这变得非常复杂,获取 PID 也并不总是那么简单,我想在信号处理获取管道以进行日志轮换时保留 exec 的便利性。知道如何做到这一点吗?

4

2 回答 2

0

我能够通过使用进程替换来解决这个问题。对于您的具体情况,以下可能有效。

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

为了重现这个场景,我构建了这个简单的 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

建造docker build -f Dockerfile.meu -t test .

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

停下来docker stop test

输出:

Caught a sigterm!
is the end! at -e line 1.
于 2022-02-21T00:58:07.510 回答
0

也许你想要

exec sh -c 'command | rotatelogs -n 10 stdout.log 10M'
于 2020-08-13T15:53:00.507 回答