============================
docker 微服务的优雅关闭
============================java
使用 docker stop 关闭容器时, 只有 init(pid 1)进程能收到中断信号, 若是容器的pid 1 进程是 sh 进程, 它不具有转发结束信号到它的子进程的能力, 因此咱们真正的java程序得不到中断信号, 也就不能实现优雅关闭. 解决思路是: 让pid 1 进程具有转发终止信号, 或者将 java 程序配成 pid 1 进程.git
须要说明的是, docker stop 默认是等待10秒钟, 这个时间有点过短了, 能够加 -t 参数, 好比 -t 30 等待30秒钟.github
----------------------------------
背景知识
----------------------------------docker
上面的 Dockerfile 的pid 1是一个 sh 命令,并不能实现优雅关闭, 须要再改进.shell
ENTRYPOINT/CMD 的几种写法, 会影响 pid 1 进程的产生:
写法1:
"shell" format 的 ENTRYPOINT/CMD, 不带方括号:
ENTRYPOINT top -b
#PID 1 是 /bin/sh -c shell top -b
#另外有个 pid 7 是 top -b
写法2:
"shell" format 的 ENTRYPOINT/CMD, 不带方括号, 但此次ENTRYPOINT后紧跟了一个 exec :
ENTRYPOINT exec top -b
#PID 1 是 top -b
写法3:
"exec" form 的 ENTRYPOINT/CMD, 方括号括着, 每一个部分都是json字符串.
ENTRYPOINT ["top","-b"]
pid 1 进程就是 top -b
因此推荐使用"exec" form的命令, 而不是 "shell" 形式的命令.json
----------------------------------
init 进程调整方案
----------------------------------
方案1: 自行确保 pid 1 是咱们的java程序.
上面的 Dockerfile 能够确保 java 程序做为 pid 1进程.微服务
方案评价: 有时候不太容易将咱们的主程序调整为 pid 1 进程, 另外虽然 docker 容器推荐是单进程, 但实际情形每每不是这么理想. 本方案仅仅适合单进程容器.spa
方案2: 适合于 Docker 1.13 以上.
Docker 1.13以上的docker run 命令新增了 --init 参数, 加了该参数后, docker 会启用 tini 做为 init (pid 1) 进程, 该 tini 进程可以将终止信号转发给其子进程, 同时能reap 子进程, 不会出现因孤儿进程致使的线程句柄没法回收情形.
详见: https://github.com/krallin/tini线程
方案3(推荐): 在docker镜像中强制 tini 做为 init(pid 1) 进程, 该方案使用范围广, ENTRYPOINT 能够是任意sh脚本文件.orm
改造以前的 Dockerfile
ENTRYPOINT ["/docker-entrypoint.sh"]
改造后的 Dockerfile
# Add Tini ENV TINI_VERSION v0.18.0 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini RUN chmod +x /tini ENTRYPOINT ["/usr/local/bin/tini", "--", "/docker-entrypoint.sh"]
tini 文档:
https://github.com/krallin/tini
有关 docker run --init 参数的说明
http://stackoverflow.com/a/39593409/6309
=============================== 更多推荐 =============================== https://efekahraman.github.io/2018/04/docker-awareness-in-java