任何使用docker运行的进程都必须自己处理信号。
或者使用
--init
标志运行
tini
init作为PID 1
根据您指定的命令(CMD)方式,
sh
shell可以成为PID 1进程。
详细信息:
默认情况下,
SIGTERM
由
docker run
命令传播到Docker守护程序,但除非在Docker运行的主进程中专门处理该信号,否则不会生效。
在容器中运行的第一个进程将在该容器上下文中具有PID 1。这是Linux内核对待的特殊进程。除非该进程安装了该信号的处理程序,否则它将不会收到信号。它也是PID 1的工作将信号转发到其他子进程。
docker run
和其他命令是Docker守护进程托管的远程API的API客户端。Docker守护进程作为一个独立的进程运行,并且是在容器上下文中运行的命令的父进程。这意味着run
和守护进程之间没有直接发送信号的方式,而是采用标准Unix方式。
docker run
和docker attach
命令有一个--sig-proxy
标志,默认情况下将信号代理设置为true
。如果需要,可以关闭该功能。
docker exec
不会代理信号。
在编写
Dockerfile
时,如果不想让
sh
成为 PID 1 进程(
Kevin Burke),请注意在指定
CMD
和
ENTRYPOINT
的默认值时使用 "exec 形式"。
CMD [ "executable", "param1", "param2" ]
信号处理Go示例
使用这里的Go示例代码:https://gobyexample.com/signals
运行一个不处理信号的常规进程和捕获信号并将其放入后台的Go守护程序。我使用sleep
因为它很简单且不处理"守护进程"信号。
$ docker run busybox sleep 6000 &
$ docker run gosignal &
使用具有“树形”视图的
ps
工具,您可以看到两个不同的进程树。一个是在
sshd
下的
docker run
进程树。另一个是在
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主机进程的细节:
$ 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
命令:
$ kill 4632
$
terminated
exiting
[2]+ Done docker run gosignal
通过 docker exec
发送信号
如果我在已经运行的 sleep
容器中使用 docker exec
命令启动一个新的 sleep
进程,我可以发送 ctrl-c 信号来中断 docker exec
命令本身,但这不会转发到实际的进程:
$ 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
docker run
信号实际上会做什么,所以只是瞎猜。不过我刚才看了一下,似乎docker run
进程默认情况下会通过代理传递所有信号(在此处搜索sig-proxy
)。 - slugonamission