场景1
CMD ["java", "-jar", "app.jar"]
这时候java程序的PID=1
也就是容器的主进程
执行docker stop <container>
也就等于kill -15 1
,这时候只要java程序能够处理SIGTERM
信号即可
场景2
CMD ["/home/default/start.sh"]
start.sh
#!/bin/bash
echo "[INFO] 开始运行"
java -jar app.jar
很多时候我们一般会用一个shell脚本作为容器的主进程,这样启动逻辑就很灵活
执行docker stop <container>
也就等于 kill -15 1
,shell脚本收到SIGTERM信号后并不会把信号传给它的子进程,也就是说java程序不会做任何动作,直到宽限期到期会强制关闭容器等于kill -9
docker 使用 docker stop -t
参数指定宽限期默认是10秒,kubernetes里面使用 terminationGracePeriodSeconds: 30
解决
方法1
那么shell如何传递SIGTERM信号给它的子进程?
#!/bin/bash
echo "[INFO] 开始运行"
java -jar app.jar &
pid="$!"
_kill() {
echo "[INFO] Receive sigterm"
kill $pid
wait $pid
exit 143
}
trap _kill SIGTERM
wait
步骤是把java程序后台启动以获得它的PID,最后一行加入wait
命令防止shell
退出,trap
命令捕捉SIGTERM
信号并执行一个命令
方法2
假设shell脚本里面只需求启动一个子程序,其实有更简洁的办法
#!/bin/bash
echo "[INFO] 开始运行"
exec java -jar app.jar
exec特性是不产生新的子进程而是当前shell进程,所以exec之后的命令将不会执行。