无法在Docker容器中捕获SIGINT

时间:2017-07-31 04:03:07

标签: docker go signals sigint

我有以下图片

FROM golang:1.8.3
WORKDIR /go/src/x/x/program
RUN mkdir /logs
VOLUME ["/go/src/x/x/program", "/logs"]
CMD ["sh", "-c", "go install && program"]

我的Go服务器以下列方式侦听SIGINT

// ... Other stuff

c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt)

go func() {
    <-c
    signal.Stop(c)

    // Server graceful shutdown
    err := s.Shutdown(context.Background())
    if err != nil {
        fileLogger.Printf("could not shutdown server: %v", err)
    } else {
        fileLogger.Print("server successfully shutdown")
    }

// ... Start server

但我没有陷阱和处理SIGINT。我尝试了以下方法:

  • docker kill -s SIGINT <my_container>
  • (使用撰写)docker-compose down/kill
  • docker exec -ti <my_container> /bin/bash
    • (后跟)kill -SIGINT <go program PID>

没有记录任何内容,所以我认为SIGINT根本没有被我的程序处理。

在测试时,我设法通过以下操作来做到这一点(这不适合生产)

  • docker run -ti -v <local_path_to_log>:/logs <my_image> /bin/bash
    • go run *.go
    • CTRL + C中断进程

我在文件中看到了日志。

我还想出了我的图像设置方式,它最终运行了两个进程:

docker exec -ti <my_container> /bin/bash
root@xxx:/go/src/x/x/x# ps aux | grep program
root         1  0.0  0.0   4332   716 ?        Ss   03:47   0:00 sh -c go install && program
root        32  0.0  0.3 335132  6624 ?        Sl   03:47   0:00 program
root@xxx:/go/src/x/x/x# kill -SIGINT 32

如上所示,杀死第二个进程(而不是PID 1)会将SIGINT发送给程序,而不是陷阱和处理它。

我知道我已接近从容器外部发送SIGINT的解决方案。但我还没把握住它。

这里有一个容器可以接收到正确进程的SIGINT的正确方法是什么?

1 个答案:

答案 0 :(得分:0)

Docker将信号传递给PID 1进程。在您的情况下,由于您正在生成子进程,因此您无法获得信号。 如果CMD中只有1个处理,您可以执行以下操作:

CMD ["/bin/ping","localhost"]

如果您正在执行上述操作之外的多个操作,则可以在CMD中运行脚本并在脚本中进行信号处理并将其传递给后台进程。另一种选择是在CMD中只有1个命令处理。您可以在上一步中执行“go install”,只需在CMD中运行可执行文件。