利用 trap 在 docker 容器优雅关闭前执行环境清理的方案

 更新时间:2021年12月17日 11:11:34   作者:DrunkCat90  
这篇文章主要介绍了利用 trap 在 docker 容器优雅关闭前执行环境清理的问题,需要在容器的启动脚本中,加入 trap 指令,来完成容器在退出前需要做的所有事情,本文通过脚本示例给大家介绍的非常详细,需要的朋友参考下吧

当一个运行中的容器被终止时,如何能够执行一些预定义的操作,比如在容器彻底退出之前清理环境。这是一种类似于 pre stop 的钩子体验。但 docker 本身无法提供这种能力,本文结合 Linux 内置命令 trap ,实现在容器优雅关闭之前,可以执行自定义的操作。

当一个运行中的容器被终止时,如何能够执行一些预定义的操作,比如在容器彻底退出之前清理环境。这是一种类似于 pre stop 的钩子体验。但 docker 本身无法提供这种能力,本文结合 Linux 内置命令 trap ,实现在容器优雅关闭之前,可以执行自定义的操作。

如何关闭容器

我了解有三种方式可以关闭一个正在运行中的容器,三者都是由 docker 命令行发起的。

  • 第一种是较为优雅的方式 docker stop ContainerID
  • 第二种看起来就比较武断 docker rm -f ContainerID
  • 第三种用的人会少很多 docker kill --signal=KILL ContainerID

docker 的设计者自然不会平白无故的设计三种命令组合来做关闭容器这件事,三种方式都应该在什么场景下被使用呢?

这三种终止容器的方式之间是略有不同的,在讲解这些不同之前,需要提及一些看似和容器不相关的知识点——SIGNAL 。

进程与信号

用户是可以通过发送信号,来和进程通信的。

基本上每一个运维工程师都执行过如下命令来杀死一个进程:

kill -9 PID

这个命令看起来恰如其分,我 "杀死" 了一个进程,但是,为什么是 "-9" ?

9 是信号 SIGKILL 的代号,上述命令实际上是向对应的进程发送了一个信号,一个可以杀死进程的信号。

kill 命令的真正意义,是向进程发送指定的信号,除了SIGKILL(9) 之外,还可以发送其他多种信号:

root@ubuntuserver:~# kill --help

kill: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]

    Send a signal to a job.

root@ubuntuserver:~# kill -l

 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP

 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1

11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM

16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP

21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ

26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR

31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3

38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8

43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13

48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12

53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7

58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2

63) SIGRTMAX-1 64) SIGRTMAX

我无意去详解每一个信号的意义,我的功力还差得远,在这里只拣取和我们主题相关的知识来进行阐述。

有两个信号和我们的主题相关, SIGTERM. SIGKILL

信号名称 代号 可否被捕获或忽略
SIGTERM 15 可以
SIGKILL 9 不可以

SIGTERMkill 命令默认发送的信号。当用户请求终止进程时,会产生SIGTERM信号。SIGTERM信号可以被捕获或无视。这允许该进程在结束前释放掉所占用的资源并保存其状态。

SIGKILL 发送SIGKILL信号到一个进程可以使其立即终止(KILL)。与SIGTERM不同的是,这个信号不能被捕获或忽略,接收过程在接收到这个信号时不能执行任何清理。但有时候 kill -9 并非一定可以杀死进程,释放资源。还是有一些特殊情况:

  • 僵尸进程不能被杀死,因为它们已经死了,正在等待它们的父进程来收获它们。
  • 处于阻塞状态的进程不会死亡,直到它们再次醒来init 进程是特殊的:
  • init不接收任何它不打算处理的信号,因此它会忽略SIGKILL。这条规则有一个例外,Linux 上的 init 如果被 ptrace 了,那么它是可以接收 SIGKILL 并被杀死的。
  • 处于不可中断的睡眠的进程即使发送了SIGKILL,也有可能不会终止(并释放其资源)。这是少数 Unix 系统必须重新启动才能解决临时软件问题的几种情况之一。

容器与信号

容器的本质,是一组被封装起来的进程。所以通过开头讲到的三种命令行方式关闭一个运行中的容器,其本质也是在通过发送信号的方式与容器中的进程进行交互,使之被 "杀死" 的过程。

  • docker stop

执行 docker stop ContainerID ,会向容器中的主进程先发送一个 SIGTERM 信号,在一段时间的宽限期后,发送 SIGKILL 信号彻底杀死容器。

Docker 手册原文如下:

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

  • docker rm -f

执行 docker rm -f ContainerID ,会向容器中的主进程直接发送SIGKILL 信号,在容器杀死之后,也会把容器删除掉。从删除容器这个操作看来,这个命令是用来删除一个已停止的容器,而非用于停止运行中的容器。

  • docker kill

执行 docker kill --signal=KILL ContainerID ,是专门向容器主进程发送各种自定义信号的方式。换言之,它就是面向容器的 kill 命令。当前命令是在向容器主进程发送一个 SIGKILL 信号。

通过比对,docker rm -f ContainerID 这种方式是不应该用于停止运行中容器的。而剩余两种方式之间, docker stop ContainerID 也明显要优雅一些,它既可以保证容器会被最终杀死,也会提供 SIGTERM 供用户后续捕获处理。

接下来终于要进入正题了。

捕获信号并处理

信号 SIGTERM 是一种可以被捕获的信号。当容器主进程捕获到这个信号之后,可以触发事先设计好的逻辑,在彻底退出之前完成预定的任务。比如可以执行环境的清理、数据的保存、关闭其他不受主进程控制的进程等等。在某些场景下,这种需求非常突出。

Linux 提供内置的 trap 命令,负责捕获信号,并确保在进程彻底退出前,执行某些任务。

root@ubuntuserver:~# trap --help

trap: trap [-lp] [[arg] signal_spec ...]

    Trap signals and other events.

其基本的使用方式如下:

trap do_some_things SIGSPEC

思路已经清晰了,我们需要在容器的启动脚本中,加入 trap 指令,来完成容器在退出前需要做的所有事情。

以下是一个脚本示例,这个脚本被作为容器的入口(ENTRYPOINT)执行。

#!/bin/bash

function clean_up_term {
  rm -rf /data/tmp
  echo "clean_up_term in execution"
}

trap clean_up_term SIGTERM

for ((i=1;i<=1000;i++))
  do
    echo "Wait for $i"
    sleep 1
  done 

容器启动后,从其他终端执行了 docker stop ContainerID 命令,可以观察到以下结果。

guox@MacBook-Pro-For-Guox: /Users/guox/GitHub/test-plugin git:(master) ✗ 

➜   docker run -ti --name=clean -v $(pwd)/data:/data clean 

Wait for 1

Wait for 2

Wait for 3

Wait for 4

Wait for 5

Wait for 6

Wait for 7

Wait for 8

Wait for 9

Wait for 10

Wait for 11

Wait for 12

Wait for 13

clean_up_term in execution

Wait for 14

Wait for 15

Wait for 16

Wait for 17

Wait for 18

Wait for 19

Wait for 20

Wait for 21

Wait for 22

Wait for 23

guox@MacBook-Pro-For-Guox: /Users/guox/GitHub/test-plugin git:(master) ✗ 

信号 SIGTERM 的确被容器捕获,并进行了相关的清理操作。 docker stop ContainerID 提供了一段宽限期,所以在执行了清理操作后,容器主进程还是继续执行了一会才退出。

到此这篇关于利用 trap 在 docker 容器优雅关闭前执行环境清理的文章就介绍到这了,更多相关docker 容器执行环境清理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于Docker容器内部无法解析域名问题的解决

    关于Docker容器内部无法解析域名问题的解决

    最近工作中遇到一个问题,项目内部需要访问外网,但上传文件,但是一直报unknown host,无法解析域名,所以下面这篇文章主要给大家介绍了关于Docker容器内部无法解析域名问题的解决方法,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-07-07
  • docker registry 镜像同步的实现思路

    docker registry 镜像同步的实现思路

    这篇文章主要介绍了docker registry 镜像同步的相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-06-06
  • 基于windows10安装docker及遇到的问题

    基于windows10安装docker及遇到的问题

    这篇文章主要介绍了基于windows10安装docker及遇到的问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • 如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件

    如何使用Docker部署FTP和Nginx并通过HTTP访问FTP里的文件

    本文介绍了如何使用Docker部署FTP服务器和Nginx,并通过HTTP访问FTP中的文件,通过将FTP数据目录挂载到Nginx容器内,Nginx可以提供文件列表和下载功能,推荐使用Docker Compose来管理容器
    2025-03-03
  • Docker超详细讲解镜像操作

    Docker超详细讲解镜像操作

    镜像也是 docker 的核心组件之一,镜像时容器运行的基础,容器是镜像运行后的形态。本文主要介绍Docker镜像的基本操作,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-08-08
  • docker部署xxl-job-admin出现数据库拒绝问题及解决方法

    docker部署xxl-job-admin出现数据库拒绝问题及解决方法

    这篇文章主要介绍了docker部署xxl-job-admin出现数据库拒绝问题,本文给大家分享正确的解决思路,对docker部署xxl-job-admin相关知识感兴趣的朋友一起看看吧
    2023-02-02
  • docker运行nginx容器并挂载数据卷

    docker运行nginx容器并挂载数据卷

    本文主要介绍了docker运行nginx容器,并通过挂载目录将容器与宿主机的数据进行共享和统一管理,具有一定的参考价值,感兴趣的可以了解一下
    2025-03-03
  • 告别Docker请求超时之一步步排查与详细解决方案

    告别Docker请求超时之一步步排查与详细解决方案

    在Ubuntu系统上安装Docker后,运行docker run hello-world时遇到连接超时问题,下面这篇文章主要介绍了Docker请求超时一步步排查与详细解决方案的相关资料,需要的朋友可以参考下
    2025-02-02
  • Docker 命令教程(附中文解释)

    Docker 命令教程(附中文解释)

    这篇文章主要介绍了Docker 命令教程的相关资料,在学习Docker的过程中,特地把所以命令实验了一番并整理,希望大家尽快掌握此部分的知识,有需要的小伙伴可以参考下
    2016-10-10
  • 使用docker-compose实现不停机部署/灰度发布的四种方法

    使用docker-compose实现不停机部署/灰度发布的四种方法

    灰度发布是一种软件部署策略,它允许将新版本的部分功能或服务逐步推送给用户,而不是一次性对所有用户进行大规模更新,本文主要给大家介绍了使用docker-compose实现不停机部署/灰度发布的四种方法,需要的朋友可以参考下
    2024-11-11

最新评论