Docker 中的信号

准备工作

test.py

import signal  
import os


def custom_handler(signum, frame):  
    print("received: {}".format(signum))


signal.signal(signal.SIGTERM, custom_handler)  
print("Hello World, pid is {}".format(os.getpid()))  
signal.pause()  

Dockerfile

FROM debian:latest  
RUN apt-get update && \  
    apt-get -y install python3 &&\
    apt-get clean all
COPY test.py ~/  
CMD ["/usr/bin/python3", "-u", "~/test.py"]  

构建镜像 docker build -t demo:latest .

信号机制

关于 Linux 的信号就不多说了,支持的信号种类可从 man 7 signal 中获取

Docker 支持向容器内发送信号,可以通过 docker kill <SINGAL> [container] 发送自定义信号

创建容器

sagiri ➜ docker run --name demo demo:latest  
Hello World, pid is 1  

容器中的 Python 脚本在等待信号,执行 docker kill --signal="SIGTERM" demo 后,可以看到

received: 15  

并且容器退出

另外,我们需要注意 Python 脚本的 PID 为 1。发送到 Docker 容器的信号,默认会被 PID 为 1 的进程处理,这个进程一般是 Dockerfile 中 ENTRYPOINT 或者 CMD 所执行的命令

另外一种玩法

我们还可以向 Docker 的 sock 中发送消息,比如这样

curl --unix-socket /var/run/docker.sock -X POST  http:/v1.24/containers/demo/kill -d signal="SIGTERM"  

那么假如我们现在的情景是这样的,一个 Docker 中运行 nginx,另一个 Docker 中运行某个脚本。它接受 bus 中的消息,并决定是否对 nginx 进行 reload。乍一看貌似 Docker 间是隔离的,无法相互影响。但是我们可以在脚本的 Docker 中去挂载宿主机的 docker.sock 文件,这样便可以实现这种要求