正确使用‘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 ...
随机推荐
- deque 用法
引用博客:https://blog.csdn.net/zyq522376829/article/details/46801973 下面是那位大佬写的的笔记整理~~~~ deque - 双向队列 1.构 ...
- word域代码判断奇偶插入分页符
阿拉伯数字页码判断奇偶插入分页符(PAGE表示当前页码,QUOTE 12表示插入分页符) {IF{=MOD({PAGE},2)} = 1 "{ QUOTE 12}" " ...
- python3 循环输出当前时间。
题目 暂停一秒输出(使用 time 模块的 sleep() 函数).循环输出当前时间. 代码: import time while True: time.sleep(1) print(time.str ...
- socketserver的使用
socketserver底层也是使用线程实现的并发,直接上代码 # server import socketserver ''' socketserver使用模式: 1 功能类 class Myser ...
- viewController备注
1.按结构可以对iOS的所有ViewController分成两类: 1).主要用于展示内容的ViewController,这种ViewController主要用于为用户展示内容,并与用户交互,如UIT ...
- hdu 5533
Dancing Stars on Me Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Ot ...
- poj 3050 地图5位数问题 dfs算法
题意:一个5*5地图上面,从任意位置上下左右跳五次,组成一个数.问:不重复的数有多少个? 思路:dfs 从任意位置跳5次,说明每个位置都需要遍历. 组成一个数:number*10+map[dx][dy ...
- matlab画图颜色设置
各种颜色属性选项选项意义选项意义'r' 红色 'm' 粉红'g' 绿色 'c' 青色'b' 兰色 'w' 白色'y' 黄色 'k' 黑色各种线型属性选项选项意义选项意义'-' 实线 '--' 虚线': ...
- jeecg使用uploadify上传组件
在jeecg框架的系统内使用uploadify组件进行上传操作,有时无法正常发送请求,一直被重定向到登录请求,有可能使系统对上传操作进行了过滤,需要将这个上传请求放到非拦截序列里,才能正常使用. 第二 ...
- 如何从Maven中央存储库下载?
根据 Apache Maven说明: 下载时由项目的 pom.xml 文件的依赖来决定,目前不在本地存储库触发(当中央存储库包含了一个更新).默认情况下,Maven将从中央存储库下载. 在Maven中 ...