docker 优雅的关闭 spring boot 应用容器

============================
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

相关文章
相关标签/搜索