正确的在 docker 中启动 springboot

在Docker中,正确关闭SpringBoot服务避免使用kill-9。通过设置ENTRYPOINT,让java进程成为PID1或者使用tini作为init进程,确保在容器关闭时能优雅地回收资源。此外,使用exec启动java进程也能实现优雅关闭。这种方法不仅适用于SpringBoot,也适用于其他依赖资源回收的进程。
摘要由CSDN通过智能技术生成

背景

如题,为什么说是正确的使用(更优雅的使用)呢,是因为有一个细节一定有很多人不会在意!

在 tomcat 时代、在 java -jar springboot.jar 时代,不少人关闭服务喜欢暴力的 kill -9 pid 吧?实际上我们应该给我们的程序一个喘息(回收资源)的机会,不应该加 -9(强制)。

在使用 docker 构建 springboot 应用时,你可以能会出现如下两种启动服务的方式:
1、直接在 ENTRYPOINT 中写命令

FROM openjdk:8-jdk-alpine
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java","${JAVA_OPTS}","-jar","/app.jar"]

2、编写一个 sh 启动脚本,然后在 ENTRYPOINT 中执行它

FROM openjdk:8-jdk-alpine
VOLUME /tmp
COPY run.sh .
COPY target/*.jar app.jar
ENTRYPOINT ["run.sh"]

然后对应的 run.sh 脚本内容如下:

#!/bin/sh
其他命令XXX1
其他命令XXX2
其他命令XXX3
java $JAVA_OPTS -jar /app.jar

问题

运行如上两种不同 ENTRYPOINT 方式的容器,然后进入 docker 内的命令行,使用 ps -ef 查看进程的 PID,你会发现:
1、第一种方式构建的镜像,容器启动后 java 进程的 pid 为 1
2、第二种方式构建的镜像,容器启动后 java 进程的 pid 一定不是 1,pid 为 1 的进程是我们的 run.sh 脚本

PID 是否为 1 很重要,这里划重点!

当 docker 容器被正常关闭时,只有 init(pid 1)进程能收到中断信号,如果容器的 pid 1 进程是 sh 进程,它不具备转发结束信号到它的子进程的能力(而我们第二种在 run.sh 中启动的 java 进程是 pid 为 1 的 run.sh 进程的子进程),所以我们真正的 java 程序得不到中断信号,springboot 也就不能正常的回收资源(比如正在执行中的线程不能正常的执行结束),也就不能实现优雅关闭(会导致我们程序被暴力终止无法善始善终)。

解决

根据上文内容,得出解决 “run.sh” 方式启动服务的思路:
1、让pid 1 进程具备转发终止信号
2、或者将 java 程序配成 pid 1 进程

方法1:
在 docker 镜像中配置 tini 作为 init(pid 1)进程,因为 tini 具备转发信号的能力(tini官方地址
编辑 Dockerfile 文件,添加如下内容:

# Add Tini
ENV TINI_VERSION v0.19.0 
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /sbin/tini
RUN chmod +x /sbin/tini

修改 ENTRYPOINT

ENTRYPOINT [ "/sbin/tini", "--", "run.sh"]

像 jenkins、rancher 等中间件也使用了这样的方式

方法2:
在 run.sh 中,使用 exec 启动 java 子进程。

注:使用exec command方式,会用command进程替换当前shell进程,并且保持PID不变。执行完毕,直接退出,不回到之前的shell环境。

这里就不需要修改 Dockerfile 文件了,我们需要修改启动脚本(run.sh),内容如下:

#!/bin/sh
其他命令XXX1
其他命令XXX2
其他命令XXX3
exec java $JAVA_OPTS -jar /app.jar

至此,问题解决,可以构建镜像后运行容器,通过 ps -ef 查看 pid,这样以来当我们正常停止容器时,容器内部的 springboot 服务程序在收到信号后,会执行相关的资源回收操作(比如很多 destroy 方法等)。

注:
1、本文所述内容,不仅仅适用于标题所指的 springboot 服务,同样适用于其他任何类似场景的子进程。
2、最后还是提醒大家,非必须情况尽量不要使用 kill -9,请善待你的服务。


(END)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

catoop

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值