一般应用(比如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优雅退出的更多相关文章

  1. Node 出现 uncaughtException 之后的优雅退出方案

    Node 的异步特性是它最大的魅力,但是在带来便利的同时也带来了不少麻烦和坑,错误捕获就是一个.由于 Node 的异步特性,导致我们无法使用 try/catch 来捕获回调函数中的异常,例如: try ...

  2. NodeJS服务器退出:完成任务,优雅退出

    上一篇文章,我们通过一个简单的例子,学习了NodeJS中对客户端的请求(request)对象的解析和处理,整个文件共享的功能已经完成.但是,纵观整个过程,还有两个地方明显需要改进: 首先,不能共享完毕 ...

  3. golang channel详解和协程优雅退出

    非缓冲chan,读写对称 非缓冲channel,要求一端读取,一端写入.channel大小为零,所以读写操作一定要匹配. func main() { nochan := make(chan int) ...

  4. golang中使用Shutdown特性对http服务进行优雅退出使用总结

    golang 程序启动一个 http 服务时,若服务被意外终止或中断,会让现有请求连接突然中断,未处理完成的任务也会出现不可预知的错误,这样即会造成服务硬终止:为了解决硬终止问题我们希望服务中断或退出 ...

  5. .NET Worker Service 如何优雅退出

    上一篇文章中我们了解了 .NET Worker Service 的入门知识[1],今天我们接着介绍一下如何优雅地关闭和退出 Worker Service. Worker 类 从上一篇文章中,我们已经知 ...

  6. .NET Worker Service 作为 Windows 服务运行及优雅退出改进

    上一篇文章我们了解了如何为 Worker Service 添加 Serilog 日志记录,今天我接着介绍一下如何将 Worker Service 作为 Windows 服务运行. 我曾经在前面一篇文章 ...

  7. 优雅退出在Golang中的实现

    背景 为什么需要优雅关停 在Linux下运行我们的go程序,通常有这样2种方式: 前台启动.打开终端,在终端中直接启动某个进程,此时终端被阻塞,按CTRL+C退出程序,可以输入其他命令,关闭终端后程序 ...

  8. Docker 优雅终止方案

    作为一名系统工程师,你可能经常需要重启容器,毕竟Kubernetes的优势就是快速弹性伸缩和故障恢复,遇到问题先重启容器再说,几秒钟即可恢复,实在不行再重启系统,这就是系统重启工程师的杀手锏.然而现实 ...

  9. 优雅退出 Android 应用程序的 6 种方式

    我们先来看看几种常见的退出方法(不优雅的方式) 一.容器式 建立一个全局容器,把所有的Activity存储起来,退出时循环遍历finish所有Activity import java.util.Arr ...

随机推荐

  1. 如何下载并安装 robomongo 到Ubuntu 系统

    官网下载软件,https://robomongo.org/download wget https://download.robomongo.org/1.2.1/linux/robo3t-1.2.1-l ...

  2. 1、python-初探

    语言包括编译型语言和解释型语言编译型:全部翻译,再执行:c.c++解释型:边执行边翻译:python.php.java.c#.perl.ruby.javascript 一.系统位数32位系统内存的最大 ...

  3. python并发编程之线程剩余内容(线程队列,线程池)及协程

    1. 线程的其他方法 import threading import time from threading import Thread,current_thread def f1(n): time. ...

  4. POJ:2777-Count Color(线段树+状压)

    Count Color Time Limit: 1000MS Memory Limit: 65536K Description Chosen Problem Solving and Program d ...

  5. 带权并查集:HDU3172-Virtual Friends

    Virtual Friends Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Tot ...

  6. 重新造轮子之静态链接1(Static linking)

    最近学习计算机病毒学的过程中,又讲到了静态链接的问题,联想到了之前保健哥在信息安全的课堂上向我们展示了一个没有main()函数的C程序到底应该如何编写.个人觉得这个小实验对于加深静态链接的过程的理解也 ...

  7. VS2017生成.net core项目报错:The current .NET SDK does not support targeting .NET Core 2.1. Either

    今天在生成一个项目的时候,生成报错,错误如下:The current .NET SDK does not support targeting .NET Core 2.1.  Either target ...

  8. 虚拟机上的Linux学习

    title: 虚拟机上的Linux学习 date: 2018-08-08 15:48:28 updated: tags: [Linux,学习笔记] description: keywords: com ...

  9. Java程序的结构和执行

    目录 Java程序的结构 Java程序的执行 source code -- compiler -- class file -- JVM compiler JVM Java语法 数据类型 数据的存储 堆 ...

  10. TensorFlow笔记——

    主要依赖包 protocal buffer 处理结构化数据的工具:序列化(结构化数据->数据流) + 还原(数据流->结构化数据) protocol buffer与XML和JSON的区别: ...