docker 关闭Container的思路:当我们使用docker stop 命令去关闭Container时,该命令会发送SIGTERM 命令到Container主进程,让主进程处理该信号,关闭Container,如果在10s内,未关闭容器,docker Damon会发送SIGKILL 信号将Container关闭。
Signal
Signal 表示内部进程的一种通信机制,一个信号表示一个从内核发送到进程的消息,该消息表示某个事件已经发生,当进程收到该信号,进程会被打断,一个信号处理句柄会处理该信号,如果没有针对该信号的句柄,会使用默认句柄处理该信号。
进程会将自己可以处理的信号以回调函数的方式注册到系统内核,当你在终端执行一个Kill命令时,实际上你是在通知内核向其他进程发送信号。一个常见的信号时 SIGTERM,该信号时通知进程关闭并终止,当进程收到该信号时,可以执行关闭Socket、数据库连接、删除临时文件等。许多守护进程会处理SIGHUP信号,从而能够重新加载配置文件,SIGUSR1和SIGUSR2是用户自定义的信号,可以在应用中处理该信号。
举例,在Node.js中处理SIGTERM信号
1 | process.on('SIGTERM', function() { |
当进程处理SIGTERM信号时,处理该信号的句柄会将程序的执行打断,当该句柄执行完成后,程序才会继续运行,常见的信号如下表所示, 除了SIGKILL 和SIGSTOP信号外,其他信号都可以被进程终止
docker中的信号
docker命令“docker kill”向容器内的主进程发送信号
1 | Usage: docker kill \[OPTIONS\] CONTAINER \[CONTAINER...\] |
发送到容器的信号被容器的主进程(PID为1)处理,主进程可以忽略该信号,让默认的操作执行,或者为该信号提供一个回调函数。
举例,在容器内运行一个应用,检查信号处理句柄。
1 | var http = require('http'); |
我们创建了一个监听3000端口的http server,创建了两个信号处理句柄,分别处理SIGINT和SIGTERM信号,当信号句柄执行时,将会在标准输出打印:
`server stopped by [SIGNAL]`.
分两种场景描述
该应用是前端应用
当应用是该容器的主进程时,他能够直接处理信号,以下该应用的dockerfile文件
1 | FROM iojs:onbuild |
当在编写dockerfile文件的时候,启动应用一定要使用ENTRYPOINT或者RUN 命令,否则容器内的主进程将会是/bin/sh –c ,应用只能是主进程的子进程,如果是这样的话,应用是无法收到信号的。
构建镜像:
$ docker build -t signal-fg-app .
运行容器
$ docker run -it –rm -p 3000:3000 –name=”signal-fg-app” signal-fg-app
访问 http://localhost:3000 验证应用正常运行
打开另一个终端执行docker kill 命令
$ docker kill –signal=”SIGTERM” signal-fg-app
或者
$ docker stop signal-fg-app
这两个命令都可以发送SIGTERM信号来停止应用
Both commands can be used to issue SIGTERM signal and stop the application.
在运行应用的终端,可以看到下面的输出日志
server stopped by SIGTERM
当应用是后台应用时
无法直接将信号发送到该应用,这种场景下的一种解决方法是:以shell脚本的方式启动应用,在这个启动脚本里处理全部的信号,制作该应用的Dokcerfile文件
1 | dockerfile: |
查看启动脚本program.sh
1 | #!/usr/bin/env bash |
这里我们创建了两个信号处理函数,一个是处理用户定义的信号,一个是处理SIGTEM信号,能够优雅的关闭应用。
在这个应用中,我们的应用是后台运行的(&),最后,我们使用“wait”来暂停运行,直到一个子进程退出,“wait”和“waitpid”这两个函数在收到信号时,会终止执行,当收到信号后,我们使用特定的句柄处理信号。
docker的文档中说明,SIGCHLD, SIGKILL, and SIGSTOP 是无法代管的。
构建镜像:
docker build -t signal-bg-app .
运行容器:
docker run -it –rm -p 3000:3000 –name=”signal-bg-app” signal-bg-app
打开一个新的终端,发送 SIGUSR1 信号 :
docker kill –signal=”SIGUSR1” signal-bg-app
最后停止应用
docker kill –signal=”SIGTERM” signal-bg-app
应用能够打印相应的日志,并能够优雅的关闭
结论
信号提供了一中处理异步事件的方法,容器能运行的应用可以使用信号进行消息交互。使用信号与主机内的应用进行交互、重新加载配置文件、做一些清楚工作或者多进程协作。
英文地址:
https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86#.ukb9dqt9k