我有作为docker入口点运行的bash脚本。
此脚本执行一些操作,然后进入睡眠状态。
我需要能够在发出命令时优雅地停止此脚本docker stop
。AFAIK docker 向进程 1 发送SIGTERM
信号。
所以我创建了对SIGTERM
做出反应的 bash 脚本。
没有 docker 它可以正常工作,我可以启动它,发出kill -TERM <pid>
,它会优雅地停止脚本。不幸的是,它在码头工人中不起作用。
Dockerfile:
FROM ubuntu:20.04
WORKDIR /root
COPY test.sh .
CMD ./test.sh
test.sh:
#!/bin/sh
trap 'echo TERM; exit' TERM
sleep 1 &
while wait $!
do
sleep 1 &
done
我应该如何修改脚本或 Dockerfile 以允许 docker stop 正常工作?
请注意,我不允许将-it
参数传递给docker run
。
问题来自CMD
指令的shell 形式:CMD ./test.sh
。
在这种情况下,命令使用/bin/sh -c
shell 执行。所以/bin/sh
按PID 1
运行,然后分叉test.sh
,PID 1
/bin/sh -c ./test.sh
。结果,SIGTERM
信号被发送到PID 1
并且永远不会到达test.sh
。
要更改此设置,您必须使用exec 表单:CMD ["./test.sh"]
。在这种情况下,该命令将在没有外壳的情况下执行。因此,信号将到达您的脚本。
FROM ubuntu:20.04
WORKDIR /root
COPY test.sh .
CMD ["./test.sh"]
跑和杀。
# run
docker run -d --name trap trap:latest
# send the signal
docker kill --signal=TERM trap
# check if the signal has been received
docker logs trap
# TERM
我建议你尝试使用docker kill --signal=SIGTERM <CONTAINER_ID>
。
请让我知道它是否有效。
请注意,如果您的脚本碰巧生成子进程,您可能会在 docker 退出时留下孤立进程。尝试使用 --init 标志运行,如docker run --init ...
,内置的docker-init可执行文件tini
将假定为 pid 1,并确保所有子进程(例如您的睡眠示例)将在退出时相应地终止。