正确使用‘trap指令’实现Docker优雅退出
一般应用(比如mariadb)都会有一个退出命令,用户使用类似systemctl stop ****.service方法,停止其服务时,systemd会调用其配置文件注册的退出命令,该命令执行清理资源、退出集群、输出必要日志等操作后才杀死自己的进程;在系统shutdown的时候也会有类似的流程,最大程度的保证应用正常退出,下面我们称之为“进程优雅退出”。
将应用Docker化后,一个突出的问题是,如何让进程优雅的退出,而不是强行杀死进程。Docker stop和Docker kill分别实现了优雅退出和强行退出两个操作:
Docker stop:向容器内1号进程,发送SIGTERM信号,在10S之后(可通过参数指定)再发送SIGKILL信号。
Docker kill:直接发送SIGKILL信号。
显然Docker已经考虑到应用优雅退出的问题,但在实际使用中,会遇到下面2个困难:
1. 只有1号进程才收到SIGTERM信号,但Docker中有很多1号进程为monitor或者为初始化脚本的进程,并不是工作进程,且1号进程不能处理SIGTERM信号,以mariadb为例,容器内的进程关系如下:
1 /bin/sh /usr/bin/mysqld_safe --wsrep-cluster-address=gcomm://
2 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql/ ...
其中2号进程为1号进程的子进程,虽然2号进程可以处理SIGTERM信号但其收不到该信号,而1号进程虽然能收到SIGTERM但并不能处理此信号。
2. 即使1号进程能处理SIGTERM信号,但若其有子进程为外部命令(非build in命令),且子进程为前台阻塞状态,那么1号进程在直到子进程退出前仍然不能收到SIGTERM信号。如下bash是不会处理SIGTERM信号的:
#!/bin/bash
trap 'exit 0' SIGTERM
sleep
关于这一点需要了解进程处理信号的限制:只有当进程阻塞在内建命令时才可以响应SIG信号,否则会一直等待子进程退出后再处理,如上面的bash,要等到10000秒之后才能处理SIGTERM。关于内建命令和外部命令,描述如下:
内部命令实际上是shell程序的一部分,shell不需要创建子进程,比如:exit,history,cd,echo,wait,trap等,linux系统加载运行时shell就被加载并驻留在系统内存中,一般不会fork子进程。
外部命令是linux系统中的实用程序部分,需要时才将其调用内存。一般会fork出子进程。
用type命令可以分辨内部命令与外部命令。
综上所述,对于多进程Docker,我建议在容器中使用自定义bash脚本作为容器入口,脚本中使用后台方式执行具体应用的命令,然后使用内建wait阻塞,并通过trap指令监听SIGTERM,执行应用退出操作,下面以容器化mariadb为例,描述其脚本的大概实现:
#!/bin/bash
trap 'mysqladmin -uroot -p123456 shutdown' SIGTERM
mysqld_safe --wsrep-cluster-address=gcomm://10.158.113.207,10.158.113.80,10.158.113.79 &
wait $!
以上述脚本为入口的maraidb容器内进程关系如下:
mysql 1 0.0 0.0 11628 1352 ? Ss+ 07:59 0:00 /bin/bash /usr/bin/test.sh
mysql 9 0.0 0.0 11764 1636 ? S+ 07:59 0:00 /bin/sh /usr/bin/mysqld_safe --wsrep-cluster-address=gcomm://10.158.113.207,10.158.113.80,10
mysql 188 1.0 3.7 1087368 300168 ? Sl+ 07:59 0:16 \_ /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib64/mysql/p
当执行docker stop ***的时候,该容器会自动调用mysqladmin shutdown优雅退出。
以上为个人原创,欢迎转发,并保留出处。
个人能力有限,错误之处请留言指出。
正确使用‘trap指令’实现Docker优雅退出的更多相关文章
- Node 出现 uncaughtException 之后的优雅退出方案
Node 的异步特性是它最大的魅力,但是在带来便利的同时也带来了不少麻烦和坑,错误捕获就是一个.由于 Node 的异步特性,导致我们无法使用 try/catch 来捕获回调函数中的异常,例如: try ...
- NodeJS服务器退出:完成任务,优雅退出
上一篇文章,我们通过一个简单的例子,学习了NodeJS中对客户端的请求(request)对象的解析和处理,整个文件共享的功能已经完成.但是,纵观整个过程,还有两个地方明显需要改进: 首先,不能共享完毕 ...
- golang channel详解和协程优雅退出
非缓冲chan,读写对称 非缓冲channel,要求一端读取,一端写入.channel大小为零,所以读写操作一定要匹配. func main() { nochan := make(chan int) ...
- golang中使用Shutdown特性对http服务进行优雅退出使用总结
golang 程序启动一个 http 服务时,若服务被意外终止或中断,会让现有请求连接突然中断,未处理完成的任务也会出现不可预知的错误,这样即会造成服务硬终止:为了解决硬终止问题我们希望服务中断或退出 ...
- .NET Worker Service 如何优雅退出
上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...
- .NET Worker Service 作为 Windows 服务运行及优雅退出改进
上一篇文章我们了解了如何为 Worker Service 添加 Serilog 日志记录,今天我接着介绍一下如何将 Worker Service 作为 Windows 服务运行. 我曾经在前面一篇文章 ...
- 优雅退出在Golang中的实现
背景 为什么需要优雅关停 在Linux下运行我们的go程序,通常有这样2种方式: 前台启动.打开终端,在终端中直接启动某个进程,此时终端被阻塞,按CTRL+C退出程序,可以输入其他命令,关闭终端后程序 ...
- Docker 优雅终止方案
作为一名系统工程师,你可能经常需要重启容器,毕竟Kubernetes的优势就是快速弹性伸缩和故障恢复,遇到问题先重启容器再说,几秒钟即可恢复,实在不行再重启系统,这就是系统重启工程师的杀手锏.然而现实 ...
- 优雅退出 Android 应用程序的 6 种方式
我们先来看看几种常见的退出方法(不优雅的方式) 一.容器式 建立一个全局容器,把所有的Activity存储起来,退出时循环遍历finish所有Activity import java.util.Arr ...
随机推荐
- 安装好的IIS,发布成功后打开网站出现错误
开发web项目时需要安装IIS,在安装好IIS的Windows7本上发布asp.net网站时,web程序已经映射到了本地IIS上,但运行如下错误提示“处理程序“PageHandlerFactory ...
- PHP GD库---之头像合成九宫格
public function createMosaicGroupAvatar($pic_list = array(), $bg_w = 396, $bg_h = 396) { if (!$pic_l ...
- LayoutInflater的用法
Instantiates a layout XML file into its corresponding View objects. It is never used directly. Inste ...
- GridView的RowCommand事件中获取每行控件的值
//获取当前行 GridViewRow gvr = (GridViewRow)((Control)e.CommandSource).Parent.Parent; //获取 ...
- Oracle 表空间的日常维护与管理
目录 Oracle 表空间的日常维护与管理 1.创建数据表空间 2.创建临时表空间 3.创建 UNDO 表空间 4.表空间的扩展与修改大小 5.表空间重命名 6.表空间的删除 7.更改表空间的读写模式 ...
- WCF服务编程——数据契约快速入门
WCF序列化流程 序列化 默认用户自定义类型(类和结构)并不支持序列化,因为.NET无法判断对象状态是否需要反射到流. 用户自定义类的实例支持序列化 需要添加[Serialazable].若要允许可序 ...
- python - 接口自动化测试 - ReadExcel - 读取测试数据封装
# -*- coding:utf-8 -*- ''' @project: ApiAutoTest @author: Jimmy @file: read_excel.py @ide: PyCharm C ...
- Jmeter(四)_逻辑控制器详解
循环控制器: 指定其子节点运行的次数,可以使用具体的数值,也可以设置为变量 1:勾选永远:表示一直循环下去 2:如果同时设置了线程组的循环次数和循环控制器的循环次数,那循环控制器的子节点运行的次数为两 ...
- python--eclipse第一步总结
1.SyntaxError: Non-UTF-8 code starting with '\xc4' in file C:\Users\yangqiong\workspace\create.报错 解决 ...
- java 8:I / O 基础
原文地址:https://docs.oracle.com/javase/tutorial/essential/io/index.html 说明:每一个点都有一篇详细的文章与之对应,每翻译完一篇文章会更 ...