docker停止信号java_docker容器优雅停止

由于应用镜像是由spring boot制作的,在关注docker 容器停止之前,先看下Java应用是如何处理程序停止的。

java shutdownhook

在java程序停止前,我们可能会需要一些清理工作,如关闭数据库连接池,执行一些反注册等。Runtime的addShutdownHook方法给我们提供了这样一个机制,通过这个方法,我们可以告诉JVM,在收到停止信号时,执行一些我们自定义的逻辑

/**

* Registers a new virtual-machine shutdown hook.

*

*

The Java virtual machine shuts down in response to two kinds

* of events:

*

*

*

*

The program exits normally, when the last non-daemon

* thread exits or when the {@link #exit exit} (equivalently,

* {@link System#exit(int) System.exit}) method is invoked, or

*

*

The virtual machine is terminated in response to a

* user interrupt, such as typing ^C, or a system-wide event,

* such as user logoff or system shutdown.

*

*

*

*

A shutdown hook is simply an initialized but unstarted

* thread. When the virtual machine begins its shutdown sequence it will

* start all registered shutdown hooks in some unspecified order and let

* them run concurrently. When all the hooks have finished it will then

* run all uninvoked finalizers if finalization-on-exit has been enabled.

* Finally, the virtual machine will halt. Note that daemon threads will

* continue to run during the shutdown sequence, as will non-daemon threads

* if shutdown was initiated by invoking the {@link #exit exit}

* method.

*

*

In rare circumstances the virtual machine may abort, that is,

* stop running without shutting down cleanly. This occurs when the

* virtual machine is terminated externally, for example with the

* SIGKILL signal on Unix or the TerminateProcess call on

* Microsoft Windows. The virtual machine may also abort if a native

* method goes awry by, for example, corrupting internal data structures or

* attempting to access nonexistent memory. If the virtual machine aborts

* then no guarantee can be made about whether or not any shutdown hooks

* will be run.

*

* @see #removeShutdownHook

* @see #halt(int)

* @see #exit(int)

* @since 1.3

*/

public void addShutdownHook(Thread hook)

此方法在程序正常终止或者jvm收到中断interrupt、停止信号terminate时被触发

一个程序可以注册多个shutdown hook,当JVM开始停止时,这些shutdown hooks会同时执行,相互之间没有次序

序号

执行命令

结果

说明

1

kill -9

不能触发

发送的是SIGKILL

2

kill

触发

默认的是kill -15 发送SIGERM

3

ctrl+c

触发

发送的是SIGINT

4

正常结束

触发

5

oom

触发

docker 容器内部

将java程序做成docker镜像,以容器形式执行时,我们不能直接给容器内部的java进程发送信号,此时只能通过docker命令来操作正在运行的容器。根据docker stop命令的描述,

The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL.

docker只会给容器内的主进程发送信号,所以为了使java进程能收到停止信号,触发shutdown hooks,java 进程在容器内只能作为主进程(1号进程)运行。

可以通过以下方式让Java进程作为主进程在容器中运行。

在Dockerfile中通过 CMD作为容器启动的默认命令,如:

FROM openjdk:8u212-jdk-alpine

ADD ***.jar /home

WORKDIR /home

CMD java -jar ***.jar

在Dockerfile中用exec格式的ENTRYPOINT作为容器启动的默认命令,在ENTRYPOINT对应的脚本内部,用exec启动java程序,如:

Dockerfile:

FROM openjdk:8u212-jdk-alpine

ADD spring-boot-shutdownhook-1.0-SNAPSHOT.jar /home

COPY docker-entrypoint.sh /home/docker-entrypoint.sh

WORKDIR /home

RUN chmod +x docker-entrypoint.sh

ENTRYPOINT ["./docker-entrypoint.sh"]

docker-entrypoint.sh:

#!/bin/sh

#do something

exec java -jar spring-boot-shutdownhook-1.0-SNAPSHOT.jar

linux exec 命令的意思是在当前进程内执行,并且exec命令后面的 指令就不在执行了

ENTRYPOINT command param1 param2 和 ENTRYPOINT ["/bin/sh", "param1"] 都是shell模式,pid 为1的进程都是shell,不能使Java进程收到停止信号

序号

执行命令

结果

说明

1.

docker rm -f

不能触发

直接发送SIGKILL

2.

docker stop

触发

3.

docker stack rm

触发

4.

docker service rm

触发

5.

docker service scale

触发

缩减实例个数的情况下

6.

docker service update

触发

造成实例停止的更新

If one of the Pod's containers has defined a preStop hook, the kubelet runs that hook inside of the container. If the preStop hook is still running after the grace period expires, the kubelet requests a small, one-off grace period extension of 2 seconds.

Note: If the preStop hook needs longer to complete than the default grace period allows, you must modify terminationGracePeriodSeconds to suit this.

The kubelet triggers the container runtime to send a TERMsignal to process 1 inside each container.

Note: The containers in the Pod receive the TERM signal at different times and in an arbitrary order. If the order of shutdowns matters, consider using a preStop hook to synchronize.

只有容器中的1号进程能收到SIGTERM信号,所以为了在k8s环境下,使Java进程执行shutdown hooks,需保证在容器中的Java进程是主进程

在k8s环境下,还可以通过preStop这个hook来在主进程收到TERM之前做一些事情,如果我们的Java进程在容器中不是主进程,在k8s环境下,我们可以通过如下的preStop来触发Java进程的shutdown hook

***

containers:

- image: myimage:test

lifecycle:

preStop:

exec:

command: ["/bin/sh","-c","ps|grep java|grep -v grep| awk '{ print $1 }' | xargs -I{} kill {}]

***

在preStop这个hook中,通过kill ${java 进程PID (kill 默认发送 15 SIGTERM 信号)

补充

当Java进程在容器中是1号进程时,虽然能收到SIGTERM信号,自动执行shutdown hooks,但是,利用 jmap、jstack等工具对1号进程(Java进程)进行分析时,会出现如下错误

chengaofeng@chengaofeng target % docker exec -it b6a45781b81f sh

/home # ps

PID USER TIME COMMAND

1 root 0:22 java -jar spring-boot-shutdownhook-1.0-SNAPSHOT.jar

37 root 0:00 sh

42 root 0:00 ps

/home # jmap -dump:format=b,file=dump.bin 1

1: Unable to get pid of LinuxThreads manager thread

如果想让Java进程既不是1号进程,也要能收到信号,可以利用tini来实现 ,通过让tini运行在1号进程,Java作为tini的子进程来实现

Dockerfile:

FROM openjdk:8u212-jdk-alpine

ADD spring-boot-shutdownhook-1.0-SNAPSHOT.jar /home

COPY docker-entrypoint.sh /home/docker-entrypoint.sh

WORKDIR /home

RUN chmod +x docker-entrypoint.sh

RUN apk add --no-cache tini

ENTRYPOINT ["/sbin/tini", "--","./docker-entrypoint.sh"]

docker-entrypoint.sh:

#!/bin/sh

echo "hello"

exec java -jar spring-boot-shutdownhook-1.0-SNAPSHOT.jar

启动后进入容器

chengaofeng@chengaofeng target % docker exec -it 7b04dd056973 sh

/home # ps

PID USER TIME COMMAND

1 root 0:00 /sbin/tini -- ./docker-entrypoint.sh

7 root 0:21 java -jar spring-boot-shutdownhook-1.0-SNAPSHOT.jar

37 root 0:00 sh

43 root 0:00 ps

/home # jstack 7

2020-10-21 03:31:36

Full thread dump OpenJDK 64-Bit Server VM (25.212-b04 mixed mode):

"Attach Listener" #30 daemon prio=9 os_prio=0 tid=0x000056519338b800 nid=0x38 waiting on condition [0x0000000000000000]

java.lang.Thread.State: RUNNABLE

执行docker stop 命令停止容器对应的日志

2020-10-21 03:34:16.845 INFO 7 --- [ Thread-0] o.example.shutdownhook.ShutdownHookApp : app shutdown hook executed

对应的代码

@SpringBootApplication

@Slf4j

public class ShutdownHookApp {

public static void main(String[] args) {

Runtime.getRuntime().addShutdownHook(new Thread(()->{

log.info("app shutdown hook executed");

}));

SpringApplication.run(ShutdownHookApp.class, args);

}

}

需要让Java进程时tini的直接子进程

总结

使容器内Java进程能收到停止信号有以下三种方式

通过 CMD java -jar 直接运行

以exec格式启动 ENTRYPOINT,在 ENTRYPOINT对应的脚本中,以 exec java -jar 形式启动java进程

以 exec 形式启动ENTRYPOINT,command用tini,在 ENTRYPOINT对应的脚本中,以 exec java -jar 形式启动java进程

其中前两种都是让Java进程作为一号进程运行,第三种以tini作为一号进程,Java作为tini的子进程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/525640.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2018 年你需要知道的 11 个 JavaScript 库

译者按:你可能已经用到Underscore或者Lodash。本文列举了11个常用的库来提高开发效率。为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。JavaScript依然是2018年最受欢迎、最流行的编程语言&…

云化要求下,数据库架构的演进

如今,大型企业如金融企业和银行等,在下一代的微服务架构转型要求下,需要基础软件和数据平台能够实现原生的云化,以满足微服务架构的需求。微服务,也就是一种面向服务的,有特定边界的松散耦合的架构。主要特…

java定义变量的输入_Terraform中输入变量

Terraform中输入变量把所有的信息,如access_key等全部硬编码显然是不安全的。因此需要能够参数化配置。变量定义首先需要先定义(声明)变量,放到一个.tf文件中,如:variable "access_key" {}variable "secret_key&qu…

消息中间件—简谈Kafka中的NIO网络通信模型

前面写的两篇RocketMQ源码研究笔记系列:1. 消息中间件—RocketMQ的RPC通信(一)2. 消息中间件—RocketMQ的RPC通信(二)基本上已经较为详细地将RocketMQ这款分布式消息队列的RPC通信部分的协议格式、消息编解码、通信方式…

java整属取余数_js取整数、取余数的方法

摘要:这篇JavaScript栏目下的“js取整数、取余数的方法”,介绍的技术点是“取余数、取整数、取余、取整、js、方法”,希望对大家开发技术学习和问题解决有帮助。1.丢弃小数部分,保留整数部分parseInt(5/2)2.向上取整,有小数就整数部分加1Math…

如何系统学习领域驱动设计?

一、领域驱动设计为何又焕发青春?领域驱动设计(Domain Driven Design,DDD)确实已不再青春,从 Eric Evans 出版了划时代的著作《领域驱动设计》至今,已有将近十五年的时间,在软件设计领域中&…

java当中有关循环的代码_有关Java循环的内容,编程中还是比较常用的,下面分享给大家几个循环的示例代码,练习一下。1、循环输出1到100之间所有能被3或能被4整除的数。pack...

有关Java循环的内容,编程中还是比较常用的,下面分享给大家几个循环的示例代码,练习一下。1、循环输出1到100之间所有能被3或能被4整除的数。package com.hz.loop02;/*** 1、循环输出1到100之间所有能被3或能被4整除的数。* author ztw**/publ…

java的编辑框丢失焦点_java – 捕获EditText丢失焦点

我是一名长期,自学成才的业余VB程序员,现在正在尝试自学Java和Android.我这样说,所以你会知道我不会说好语言,而且对这两种追求都是非常新的.我开发了一个Android表单,其中包含一系列EditText框,每个框的内容都要在用户填写后保存到数组中.如果用户按下Enter键,我已经想出了如何…

如何运用DDD解决团队协作与沟通问题?

领域驱动设计的核心是“领域”,因此要运用领域驱动设计,从一开始就要让团队走到正确的点上。当我们组建好了团队之后,应该从哪里开始?不是UI原型设计,不是架构设计,不是设计数据库,这些事情重要…

centos6 mysql 启动_【17-02-18】 【求助】centos6 mysql重启后无法正常启动

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼# service mysqld restartStopping mysqld: [ OK ]MySQL Daemon failed to start.Starting mysqld: [FAILED]下面是# vim /var/log/mysqld.log2017-02-16 18:32:07 12429 [Note] Plugin FEDERATED is disabled.2017-02-16 18:32:07…

微服务等于Spring Cloud?一文告诉你微服务到底是什么

作者:TIM XU 原文:https://xiaoxubeii.github.io/articles/microservices-architecture-introduction/1微服务初探什么是微服务?首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统WEB应…

在php中图片放大怎么实现,用PHP实现图片的缩放与裁剪

图片太大且规格不统一,显示的控制需要靠JavaScript来完成,用在移动设备上时显示效果不好且流量巨大,需要对现有图片库的图片进行一次处理,生成符合移动设备用的缩略图,将原来客户端JS做的工作转移到服务器端用PHP的GD库…

我们爬了上千个数据分析师信息, 你真的懂数据分析师嘛?

01 项目简介有人说,这个时代,只要站在了风口,猪都能飞起来,尤其互联网行业,千变万化,日异月殊,一不小心就错过了风口,如果没记错的话,前几年火的是App开发,后…

java游戏可以刷升级挖药材,【毕业设计】Java手机游戏设计

内容介绍原文档由会员 莎士比亚 发布论文标准WORD格式排版 67页 24714字 附程序设计源文件1 绪论1.1 手机软件现状在信息社会中,手机及其他无线设备越来越多的走进普通百姓的工作和生活,随着信息网络化的不断进展,手机及其他无线设备上网络势…

高可用Redis服务架构分析与搭建

作者:HorstXu 原文:https://www.cnblogs.com/xuning/p/8464625.html基于内存的Redis应该是目前各种Web开发业务中最为常用的Key-Value数据库了,我们经常在业务中用其存储用户登陆态(Session存储),加速一些热…

java怎么弄redis,java怎么使用redis

开始在 Java 中使用 Redis 前, 我们需要确保已经安装了 redis 服务及 Java redis 驱动,且你的机器上能正常使用 Java。Java的安装配置可以参考我们的 Java开发环境配置 接下来让我们安装 Java redis 驱动:首先你需要下载驱动包 下载 jedis.ja…

我花了14个小时找了一下长春长生们究竟卖到了哪里去

前言本文首发于个人的公众号和v2ex,事先也没想到会有这么多人关注。在这边重新编辑一下,去掉了原先前言中对此次疫苗事件背景的描述及部分不严谨的措辞。全文的观点从技术讨论出发,尽量客观中立,观点及行为为员工自发,…

java jackson 注解,java – 如何使用Jackson注释序列化此JSON?

我有以下JSON:{fields : {"foo" : "foovalue","bar" : "barvalue"}}我写了一个pojo如下:public class MyPojo {JsonProperty("fields")private List fields;static class Field {JsonProperty("…

我们分析了50万条拼多多商品数据,告诉你到底是消费升级还是降级?

作者:放开那个猕猴桃来源:人工智能与大数据生活转自:知乎,恋习Python一、缘起我在杭州有位朋友,提到有家做社交的电商很火,叫拼多多,我没有在意,直到有一天,我居然在电视…

java并发集合面试题,那些经常被问的JAVA面试题(1)—— 集合部分

【本文转自极客原创 作者:张锋 原文链接:】Java集合框架是什么?说出一些集合框架的优点?每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用&…