0x11 入口函数

  • 0x10 中提到的自启动脚本只能完成基本的自启动任务
  • 当涉及到海量数据的持久化时需要能hook到docker stop指令
  • docker stop 会向id为1的进程发送TERM信号,可以使用trap捕获

0x11.1 指定pid为1

DockerfileENTRYPOINT 有两种写法,即 execshell

# 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 :

  1. 第一个是 kill 命令并不会等待进程结束,它只负责向进程发送 SIG 信号
  2. 至于程序如何处理、什么时候处理,则与它无瓜

wait:

  • trap 会导致 wait 命令结束,以执行 trap 中的方法
  • 因此kill_jar中需要搭配一个新的wait

重点

  1. 不处理 stop信号的话docker会产生大量僵尸进程
  2. 僵尸进程会占用宿主机的资源
  3. 僵尸进程达到一定数量后宿主机会假死(等待进程释放)
  4. 这不是bug,是docker预留的接口以及特性
Last modification:June 25, 2021
如果觉得我的文章对你有用,请随意赞赏