英文:
Sending signals to Golang application in Docker
问题
我正在尝试在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
终于停止了。
我的代码中没有捕获任何信号并忽略它们。我甚至尝试修改上面的代码以捕获信号并打印出来(在我的主机上可以工作,但在容器中似乎信号从未到达程序)。
有人之前遇到过这种情况吗?我还没有尝试过其他语言的类似情况,但我可以使用Ctrl-C终止在Docker容器中运行的服务器(例如mongo
,nginx
)。为什么Golang无法接收到这些信号呢?
不确定是否有所区别,但我使用的是OSX并且使用docker-machine。
非常感谢任何帮助。
英文:
I am trying to run servers written in golang inside docker containers. For example:
package main
import "net/http"
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello"))
})
http.ListenAndServe(":3000", nil)
}
If I run this code on my local machine, I can send it a SIGINT
with <kbd>Ctrl-C</kbd> and it will close the application. When I run it inside a docker container, I can't seem to kill it with <kbd>Ctrl-C</kbd>.
# 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
I then proceeded to use docker to send signals to the container.
docker kill --signal=INT 9354f574afd4
Still running...
docker kill --signal=TERM 9354f574afd4
Still running...
docker kill --signal=KILL 9354f574afd4
Finally dead.
I'm not catching any signals in my code and ignoring them. I've even tried augmented the code above to catch signals and print them out (which works on my host, but when in the container, it's as if the signals never got to the program).
Has anyone experienced this before? I haven't tried something like this in another language, but I able to kill servers (e.g. mongo
, nginx
) using <kbd>Ctrl-C</kbd> while they're in a docker container.. Why isn't Go be getting the signals?
Not sure if this makes a difference, but I am on OSX and using docker-machine.
Any help is much appreciated.
答案1
得分: 9
你正在一个 shell 中运行你的服务器,而 shell 是接收信号的进程。除非你强制退出 shell,否则你的服务器不会退出。
当你使用 "shell" 形式的 CMD 时,它将你的服务器作为 /bin/sh -c
的参数启动。为了直接执行服务器二进制文件,你需要在 CMD 或 ENTRYPOINT 中提供一个参数数组,以可执行文件的完整路径开始。
CMD ["/go/bin/simple_server"]
在 Dockerfile 文档 中的 ENTRYPOINT 中有一个注意事项:
shell 形式阻止使用任何 CMD 或 run 命令行参数,但它的缺点是你的 ENTRYPOINT 将作为 /bin/sh -c 的子命令启动,这不会传递信号。
英文:
You are running your server inside a shell, and the shell is the process receiving the signals. Your server doesn't exit until you force the shell to quit.
When you use the "shell" form of CMD, it starts your server as an argument to /bin/sh -c
. In order to exec the server binary directly, you need to provide an array of arguments to either CMD or ENTRYPOINT, starting with the full path of the executable.
CMD ["/go/bin/simple_server"]
A note from ENTRYPOINT in the Dockerfile docs:
> The shell form prevents any CMD or run command line arguments from being used, but has the disadvantage that your ENTRYPOINT will be started as a subcommand of /bin/sh -c, which does not pass signals.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论