0x11 入口函数
- 0x10 中提到的自启动脚本只能完成基本的自启动任务
- 当涉及到海量数据的持久化时需要能hook到
docker stop
指令 docker stop
会向id为1的进程发送TERM
信号,可以使用trap
捕获
0x11.1 指定pid为1
Dockerfile
的 ENTRYPOINT
有两种写法,即 exec
和 shell
:
# exec form
ENTRYPOINT ["command", "param"]
# shell form
ENTRYPOINT command param
两者的区别在于:
exec
形式的命令会使用 PID 1 的进程shell
形式的命令会被执行为/bin/sh -c <command>
,不会执行在 PID 1 上,也就不会收到signal
所以,我们应该选择 exec
模式,让我们的程序成为 PID 1 进程。
# 启动java程序
# ENTRYPOINT ["java", "-jar", "app.jar"]
# 自定义启动脚本
ENTRYPOINT ["./entrypoint.sh"]
0x11.2 trap捕获
entrypoint.sh
中利用trap
捕获信号
#!/bin/sh
echo 'Do something'
kill_jar() {
echo 'Received TERM'
kill "$(ps -ef | grep java | grep app | awk '{print $1}')"
wait $! #等待kill执行完成
echo 'Process finished'
}
trap 'kill_jar' TERM INT
java -jar app.jar &
# 等待java退出
wait $!
代码解析:
kill
:
- 第一个是
kill
命令并不会等待进程结束,它只负责向进程发送SIG
信号 - 至于程序如何处理、什么时候处理,则与它无瓜
wait
:
trap
会导致wait
命令结束,以执行trap
中的方法- 因此
kill_jar
中需要搭配一个新的wait
重点
- 不处理
stop
信号的话docker会产生大量僵尸进程 - 僵尸进程会占用宿主机的资源
- 僵尸进程达到一定数量后宿主机会假死(等待进程释放)
- 这不是bug,是docker预留的接口以及特性