将信号发送给在Docker中运行的Golang应用程序

huangapple go评论89阅读模式
英文:

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容器中运行的服务器(例如mongonginx)。为什么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 &amp;&amp; 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 &amp;&amp; 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 [&quot;/go/bin/simple_server&quot;]

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.

huangapple
  • 本文由 发表于 2015年10月28日 06:26:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/33379567.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定