我正在尝试在 docker 容器内运行用 golang 编写的服务器。例如:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello"))
})
http.ListenAndServe(":3000", nil)
}
如果我在本地计算机上运行此代码,我可以使用
Ctrl-C向其发送
SIGINT
,它将关闭应用程序。当我在 docker 容器内运行它时,我似乎无法使用 Ctrl-C 杀死它。
# Dockerfile
FROM ubuntu:14.04
RUN apt-get update && apt-get -y upgrade
RUN apt-get install -y golang
ENV GOPATH /go
COPY . /go/src/github.com/ehaydenr/simple_server
RUN cd /go/src/github.com/ehaydenr/simple_server && go install
CMD /go/bin/simple_server
然后我继续使用 docker 向容器发送信号。
docker kill --signal=INT 9354f574afd4
仍在运行...
docker kill --signal=TERM 9354f574afd4
仍在运行...
docker kill --signal=KILL 9354f574afd4
终于死了。
我没有在代码中捕获任何信号并忽略它们。我什至尝试增强上面的代码来捕获信号并将其打印出来(这在我的主机上工作,但在容器中时,就好像信号从未到达程序一样)。
有人经历过这种情况吗?我还没有在其他语言中尝试过类似的操作,但是当服务器位于 docker 容器中时,我可以使用
Ctrl-C来杀死服务器(例如
mongo
、nginx
)。为什么不 Go 是收到信号了吗?
不确定这是否有什么不同,但我在 OSX 上并使用 docker-machine。
非常感谢任何帮助。
您正在 shell 中运行服务器,而 shell 是接收信号的进程。在您强制 shell 退出之前,您的服务器不会退出。
当您使用 CMD 的“shell”形式时,它会作为
/bin/sh -c
的参数启动您的服务器。为了直接执行服务器二进制文件,您需要向 CMD 或 ENTRYPOINT 提供一组参数,从可执行文件的完整路径开始。
CMD ["/go/bin/simple_server"]
来自 Dockerfile 文档中 ENTRYPOINT 的注释:
shell 形式可以防止使用任何 CMD 或运行命令行参数,但缺点是您的 ENTRYPOINT 将作为 /bin/sh -c 的子命令启动,它不传递信号。