1、前言
● 容器中部署的時候每每都是直接運行二進制文件或命令,這樣對於容器的做用更加直觀,可是也會出現新的問題,好比子進程的資源回收、釋放、託管等,處理很差,便會成爲可怕的殭屍進程
● 本文主要討論一下docker容器中進程之間信號處理以及對進程管理的問題nginx
2、環境準備
組件 | 版本 |
---|---|
OS | Ubuntu 18.04.1 LTS |
docker | 18.06.0-ce |
3、測試腳本
首先準備一個測試腳本,該腳本主要的做用是接收信號量以及獲取信號發送者的進程號:git
semaphore.cgithub
#include <stdio.h> #include <signal.h> #include <unistd.h> #include <stdlib.h> static struct sigaction siga; static void signal_handler(int sig, siginfo_t *siginfo, void *context) { pid_t sender_pid = siginfo->si_pid; if(sig == SIGTERM) { printf("received sign: [term] , the sender is [%d]\n", (int)sender_pid); return; } return; } void main(int argc, char *argv[]) { printf("process [%d] started...\n", getpid()); siga.sa_sigaction = *signal_handler; siga.sa_flags |= SA_SIGINFO; sigaction(SIGTERM, &siga, NULL); while(1) { sleep(10); } }
測試一下:docker
首先編譯運行ubuntu
root@k8s-master:/tmp# gcc semaphore.c root@k8s-master:/tmp# ./a.out process [20765] started...
從新打開一個控制檯,發送一個SIGTERM信號bash
root@k8s-master:~# echo $$ 20638 root@k8s-master:~# kill -15 20765
查看第一個控制檯網絡
root@k8s-master:/tmp# ./a.out process [20765] started... received sign: [term] , the sender is [20638]
看起來腳本已經能夠正常工做了
它監聽了發送來得SIGTERM信號,而且成功找出了發送者ide
注:
SIGTERM是殺或的killall命令發送到進程默認的信號,SIGTERM相似於問一個進程終止可好,讓清理文件和關閉。說白了,就是對溫柔的對待,而不是粗暴的霸王硬上弓測試
4、進程在docker中收到的信號量
進程做爲docker容器中1號進程
1號進程是全部進程的父進程,它能夠收到從docker引擎發送的信號量,從而溫柔的關閉進程code
root@k8s-master:/tmp# docker run --name sem_test --rm -it -v /tmp/a.out:/a.out ubuntu:latest /a.out process [1] started...
從新打開一個控制檯
root@k8s-master:~# docker stop sem_test sem_test
回到第一個控制檯
root@k8s-master:/tmp# docker run --name sem_test --rm -it -v /tmp/a.out:/a.out ubuntu:latest /a.out process [1] started... received sign: [term] , the sender is [0] root@k8s-master:/tmp#
做爲1號進程確實正確收到了來自docker引擎的SIGTERM,此時它能夠從容的清理掉內存棧、網絡鏈接等資源
進程不是docker1號進程
root@k8s-master:~# docker exec -it sem_test bash root@77e2d4e0ed03:/# /a.out [1] 19 process [19] started...
從新打開一個控制檯,查看進程樹
查看進程樹狀態
root@c8d8af54136a:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 07:52 pts/0 00:00:00 bash root 15 1 0 07:52 pts/0 00:00:00 /a.out root 16 0 3 07:53 pts/1 00:00:00 bash root 27 16 0 07:53 pts/1 00:00:00 ps -ef
1號進程是一個很是普通的bash,a.out只不過是它的子進程而已
這時的a.out還能正確的接收到SIGTERM嗎?
root@k8s-master:~# docker stop sem_test sem_test
查看第一個控制檯狀態:
root@k8s-master:/tmp# docker run --name sem_test --rm -it -v /tmp/a.out:/a.out ubuntu:latest bash root@c8d8af54136a:/# /a.out process [15] started... root@k8s-master:/tmp#
很遺憾,a.out沒有收到SIGTERM,它被霸王硬上弓了
注:
根據docker官網docker stop的介紹:
The main process inside the container will receive SIGTERM, and after a grace period, SIGKILL.
docker stop會發送SIGTERM讓應用程序回收資源,過了溫柔期以後,會直接kill掉
5、dumb-init
● 從上面的測試來看,docker stop會向容器的1號進程發送SIGTERM
● 可是一個普通的1號進程收到SIGTERM並不會向它的子進程作任何處理
● 因此咱們須要一個優秀的父進程來接收來自docker的信號,而且傳遞給它的兒子們
dumb-init能夠幫助咱們解決1號進程的問題:
https://github.com/Yelp/dumb-init
下載一個最新版:
wget https://github.com/Yelp/dumb-init/releases/download/v1.2.2/dumb-init_1.2.2_amd64 -O dumb-init
經過dumb-init運行a.out
root@k8s-master:/tmp# docker run --name sem_test --rm -it -v /tmp/a.out:/a.out -v /tmp/dumb-init:/dumb-init ubuntu:latest /dumb-init /a.out process [8] started...
打開一個新的控制檯查看進程樹:
root@k8s-master:/tmp# docker exec -it sem_test bash root@09d494ac6ae3:/# ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 08:08 ? 00:00:00 /dumb-init /a.out root 8 1 0 08:08 pts/0 00:00:00 /a.out root 9 0 3 08:09 pts/1 00:00:00 bash root 20 9 0 08:09 pts/1 00:00:00 ps -ef
此時,1號進程變成了dumb-init,而且a.out是它的子進程
關閉容器:
root@k8s-master:/tmp# docker stop sem_test sem_test
查看狀態:
root@k8s-master:/tmp# docker run --name sem_test --rm -it -v /tmp/a.out:/a.out -v /tmp/dumb-init:/dumb-init ubuntu:latest /dumb-init /a.out process [8] started... received sign: [term] , the sender is [1] root@k8s-master:/tmp#
a.out成功收到來自1號進程(dumb-init)發送的信號SIGTERM,這下它能夠從容的回收本身的資源了
6、小結
● docker引擎會向容器中1號進程發送信號,若是你的1號進程具有處理子進程各類狀態的能力,那徹底能夠直接啓動(好比nginx會處理它的worker進程);不然就須要使用像dumb-init之類的來充當1號進程
● 關於容器中殭屍進程的測試(像bash、sleep之類的普通進程可否接管孤兒進程),本文並無進行測試
至此,本文結束 在下才疏學淺,有撒湯漏水的,請各位不吝賜教...