通过发送SIGTERM来停止正在运行的Docker容器 [英] Stop a running Docker container by sending SIGTERM

查看:129
本文介绍了通过发送SIGTERM来停止正在运行的Docker容器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常简单的Go应用,正在8080端口上监听

I have a very very simple Go app listening on port 8080

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(200)
    w.Header().Set("Content-Type", "text-plain")
    w.Write([]byte("Hello World!"))
})
log.Fatal(http.ListenAndServe(":8080", http.DefaultServeMux))

我将其安装在Docker容器中并像这样启动它:

I install it in a Docker container and start it like so:

FROM golang:alpine
ADD . /go/src/github.com/myuser/myapp
RUN go install github.com/myuser/myapp
ENTRYPOINT ["/go/bin/myapp"]
EXPOSE 8080

然后我使用 docker run 运行容器:

docker run --publish 8080:8080 first-app

我希望像大多数程序一样,我可以将SIGTERM发送到运行 docker run 的进程,这将导致容器停止运行。我观察到发送SIGTERM无效,而是需要使用 docker kill docker stop 之类的命令。

I expect that, like most programs, I can send a SIGTERM to the process running docker run and this will cause the container to stop running. I observe that sending SIGTERM has no effect, and instead I need to use a command like docker kill or docker stop.

这是预期的行为吗?我已经在论坛中问过

Is this intended behavior? I've asked in the forums and on IRC and gotten no answer.

推荐答案

A SIGTERM 默认情况下,它是通过 docker run 命令传播到Docker守护进程的,但是除非该信号在Docker运行的主进程中专门处理,否则它不会生效。

A SIGTERM is propagated by the docker run command to the Docker daemon by default but it will not take effect unless the signal is specifically handled in main process being run by Docker.

您在容器中运行的第一个进程在该容器上下文中将具有PID 1。 linux内核将其视为特殊过程。除非进程为该信号安装了处理程序,否则不会发送信号。 PID 1的任务是将信号转发到其他子进程。

The first process you run in a container will have PID 1 in that containers context. This is treated as a special process by the linux kernel. It will not be sent a signal unless the process has a handler installed for that signal. It is also PID 1's job to forward signals onto other child processes.

docker run 和其他命令是远程API 。 docker守护程序作为单独的进程运行,并且是您在容器上下文中运行的命令的父代。这意味着在 run 与守护程序之间没有以标准的unix方式直接发送信号。

docker run and other commands are API clients for the Remote API hosted by the docker daemon. The docker daemon runs as a seperate process and is the parent for the commands you run inside a container context. This means that there is no direct sending of signals between run and the daemon, in the standard unix manner.

docker run docker attach 命令有一个-sig-proxy 标志,默认标志为 true 。您可以根据需要关闭此功能。

The docker run and docker attach command have a --sig-proxy flag that defaults signal proxying to true. You can turn this off if you want.

docker exec 不代理信号

Dockerfile 中,在指定 CMD ENTRYPOINT 默认为 sh 成为PID 1进程( Kevin Burke ):

In a Dockerfile, be careful to use the "exec form" when specifying CMD and ENTRYPOINT defaults if you don't want sh to become the PID 1 process (Kevin Burke):

CMD ["executable", "param1", "param2"]



信号处理Go示例



在此处使用示例Go代码: https://gobyexample.com/signals

同时运行一个不处理信号,并捕获信号并将其置于后台的Go守护程序。我正在使用 sleep ,因为它很容易并且不处理守护程序信号。

Run both a regular process that doesn't handle signals and the Go daemon that traps signals and put them in the background. I'm using sleep as it's easy and doesn't handle "daemon" signals.

$ docker run busybox sleep 6000 &
$ docker run gosignal &

使用 ps 工具具有树视图,您可以看到两个不同的过程树。一个用于 sshd 下的 docker run 进程。另一个用于实际容器进程,位于 docker daemon 下。

With a ps tool that has a "tree" view, you can see the two distinct process trees. One for the docker run process under sshd. The other for the actual container processes, under docker daemon.

$ pstree -p
init(1)-+-VBoxService(1287)
        |-docker(1356)---docker-containe(1369)-+-docker-containe(1511)---gitlab-ci-multi(1520)
        |                                      |-docker-containe(4069)---sleep(4078)
        |                                      `-docker-containe(4638)---main(4649)
        `-sshd(1307)---sshd(1565)---sshd(1567)---sh(1568)-+-docker(4060)
                                                          |-docker(4632)
                                                          `-pstree(4671)

docker主机进程的详细信息:

The details of docker hosts processes:

$ ps -ef | grep "docker r\|sleep\|main"
docker    4060  1568  0 02:57 pts/0    00:00:00 docker run busybox sleep 6000
root      4078  4069  0 02:58 ?        00:00:00 sleep 6000
docker    4632  1568  0 03:10 pts/0    00:00:00 docker run gosignal
root      4649  4638  0 03:10 ?        00:00:00 /main



杀死



我无法杀死 docker run busybox sleep 命令:

$ kill 4060
$ ps -ef | grep 4060
docker    4060  1568  0 02:57 pts/0    00:00:00 docker run busybox sleep 6000

我可以杀死具有陷阱处理程序的 docker run gosignal 命令:

I can kill the docker run gosignal command that has the trap handler:

$ kill 4632
$ 
terminated
exiting

[2]+  Done                       docker run gosignal



通过 docker exec的信号



如果我 docker exec 在已经运行的 sleep sleep 进程$ c>容器,我可以发送ctrl-c并中断 docker exec 本身,但这不会转发到实际过程:

Signals via docker exec

If I docker exec a new sleep process in the already running sleep container, I can send an ctrl-c and interrupt the docker exec itself, but that doesn't forward to the actual process:

$ docker exec 30b6652cfc04 sleep 600
^C
$ docker exec 30b6652cfc04 ps -ef
PID   USER     TIME   COMMAND
    1 root       0:00 sleep 6000   <- original
   97 root       0:00 sleep 600    <- execed still running
  102 root       0:00 ps -ef



TL; DR



任何使用docker 运行的进程都必须处理信号

TL;DR

Any process you run with docker must handle signals itself.

或使用-init 标志运行 tini 作为PID 1

or use the --init flag to run tini as PID 1

这篇关于通过发送SIGTERM来停止正在运行的Docker容器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆