Docker中Go Web Server无法响应中断信号,如何实现Ctrl+C停止?
解决Docker容器内Go Web Server无法响应Ctrl+C中断的问题
这个问题的核心原因是:你用go run main.go作为容器启动命令时,实际运行的PID 1进程是go工具链进程,而不是你的Web服务器进程。Docker只会将中断信号(SIGINT,也就是Ctrl+C触发的信号)发送给容器内的PID 1进程,但go进程默认不会把这个信号转发给它fork出来的服务器子进程,导致服务器和容器都无法正常停止。
下面给你两种可靠的解决方案:
方案1:预编译二进制再运行(推荐)
最稳妥的方式是在构建镜像时先把Go代码编译成二进制可执行文件,然后直接运行这个二进制,让它成为容器的PID 1进程。修改你的Dockerfile如下:
FROM golang:1.11.4-alpine3.8 WORKDIR /go/src/server COPY main.go main.go # 编译生成二进制可执行文件 RUN go build -o goserver main.go # 直接运行二进制,此时它是容器的PID 1进程 CMD ["./goserver"]
重新构建并运行:
docker build -t goserver . docker run -p 1818:1818 goserver
现在按下Ctrl+C,http.ListenAndServe会接收到SIGINT信号并优雅关闭服务器,容器也会随之停止。
方案2:使用进程管理器传递信号(适合临时调试场景)
如果因为调试需求必须用go run,可以借助tini这个轻量级进程管理器来负责信号转发,确保你的服务器进程能收到中断信号。修改Dockerfile如下:
FROM golang:1.11.4-alpine3.8 # 安装tini进程管理器 RUN apk add --no-cache tini WORKDIR /go/src/server COPY main.go main.go # 让tini作为PID 1进程,负责转发信号给子进程 ENTRYPOINT ["/sbin/tini", "--"] CMD ["go", "run", "main.go"]
或者更简单的方式,用exec命令让go run进程成为PID 1:
FROM golang:1.11.4-alpine3.8 WORKDIR /go/src/server COPY main.go main.go CMD ["sh", "-c", "exec go run main.go"]
这两种方式都能让中断信号正确传递到你的服务器进程,解决Ctrl+C无法停止容器的问题。
内容的提问来源于stack exchange,提问作者Persi
相关产品推荐
相关产品推荐

