正確使用 trap指令 實現Docker優雅退出

2021-10-02 02:12:53 字數 2067 閱讀 6565

一般應用(比如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 10000

關於這一點需要了解程序處理訊號的限制:只有當程序阻塞在內建命令時才可以響應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: &

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:

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優雅退出。

c語言使用預編譯指令的正確姿勢!

為什麼防止標頭檔案重複引用?標頭檔案重複引用會報錯嗎?其實標頭檔案的重複引用大多數情況下不會出現錯誤。那什麼情況會出錯呢?小二,直接上 好嘞,客官您慢用!5個檔案分別是a.h,a.c,b.h,b.c和hello.c。在hello中為了使用a.c和b.c分別加入a.h和b.h的標頭檔案。如下 int ...

ffmpeg使用指令實現推流實現直播流程

windows下用ffmpeg nginx rtmp搭建直播環境 實現推流 拉流 啟動nginx 進入nginx的目錄,執行其中rtmp檔案。執行下列 cd g studyprojects setupvideoservice nginx 1.7.11 3 gryphon nginx.exe c co...

正確地使用Redis的SETNX實現鎖機制

setnx,是set if not exists 的縮寫,也就是只有不存在的時候才設定,設定成功時返回 1 設定失敗時返回 0 可以利用它來實現鎖的效果,但是很多人在使用的過程中都有一些問題沒有考慮到。例如某個查詢資料庫的介面因為請求量比較大所以加了快取,並設定快取過期後重新整理。當併發量比較大並且...