優雅地關閉kubernetes中的nginx

SIGINT SIGTERM SIGKILL區別

三者都是結束/終止進程運行。html

1.SIGINT SIGTERM區別

前者與字符ctrl+c關聯,後者沒有任何控制字符關聯。
前者只能結束前臺進程,後者則不是。java

2.SIGTERM SIGKILL的區別

前者能夠被阻塞、處理和忽略,可是後者不能夠。KILL命令的默認不帶參數發送的信號就是SIGTERM.讓程序有好的退出。由於它能夠被阻塞,因此有的進程不能被結束時,用kill發送後者信號,便可。即:kill-9 進程號。nginx

圖片描述

docker stop與docker kill

docker stop

當咱們用docker stop命令來停掉容器的時候,docker默認會容許容器中的應用程序有10秒的時間用以終止運行。git

在docker stop命令執行的時候,會先向容器中PID爲1的進程(main process)發送系統信號SIGTERM,而後等待容器中的應用程序終止執行,若是等待時間達到設定的超時時間,或者默認的10秒,會繼續發送SIGKILL的系統信號強行kill掉進程。在容器中的應用程序,能夠選擇忽略和不處理SIGTERM信號,不過一旦達到超時時間,程序就會被系統強行kill掉,由於SIGKILL信號是直接發往系統內核的,應用程序沒有機會去處理它。github

docker kill

默認狀況下,docker kill命令不會給容器中的應用程序有任何gracefully shutdown的機會。它會直接發出SIGKILL的系統信號,以強行終止容器中程序的運行。web

與docker stop命令不同的地方在於,docker kill沒有任何的超時時間設置,它會直接發送SIGKILL信號,以及用戶經過signal參數指定的其餘信號。docker

docker stop命令,更相似於Linux系統中的kill命令,兩者都是發送系統信號SIGTERM。而docker kill命令,更像是Linux系統中的kill -9或者是kill -SIGKILL命令,用來發送SIGKILL信號,強行終止進程。api

關於pid爲1的進程

process ID爲1的進程,一般是UNIX init進程, 在操做系統中有重要的做用:每當一個進程退出了,若是它還有子進程存在,則該子進程變成了孤兒進程,init進程過來接管。Unix被設計爲這樣一種方式,父進程必須明確地「等待」子進程終止,以便收集它的退出狀態。bash

子進程在結束後,內核仍然會爲其維護一個基本的結構,保存其pid, 退出緣由和狀態等信息,父進程經過waitpid系統調用,能夠得到這些信息。若是父進程沒有調用waitpid,這些狀態信息會一直保留,變成所謂殭屍進程。若是子進程後於父進程結束,通常來講, init進程會負責這些孤兒進程。服務器

根據通常一個容器只運行一個進程的原則,對於一個web服務,它在容器中運行時的pid是1,假設它調用了bash的cgi腳本,而這個腳本又調用了grep,一段時間後,cgi腳本由於某種緣由超時,web服務開始嘗試殺死它,可是grep卻並未受到影響,所以變成了孤兒進程。這時,pid=1的web服務應該能接管,可是絕大多數的web服務並無init那樣的能力,因此grep就變成了殭屍進程。

kubernetes的pod關閉機制

pod表明着一個集羣中節點上運行的進程,讓這些進程再也不被須要,優雅的退出是很重要的(與粗暴的用一個KILL信號去結束,讓應用沒有機會進行清理操做)。用戶應該能請求刪除,而且在室進程終止的狀況下能知道,並且也能保證刪除最終完成。當一個用戶請求刪除pod,系統記錄想要的優雅退出時間段,在這以前Pod不容許被強制的殺死,TERM信號會發送給容器主要的進程。一旦優雅退出的期限過了,KILL信號會送到這些進程,pod會從API服務器其中被刪除。若是在等待進程結束的時候,Kubelet或者容器管理器重啓了,結束的過程會帶着完整的優雅退出時間段進行重試。

一個示例流程:

  • 1.用戶發送一個命令來刪除Pod,默認的優雅退出時間是30秒

  • 2.API服務器中的Pod更新時間,超過該時間Pod被認爲死亡

  • 3.在客戶端命令的的裏面,Pod顯示爲"Terminating(退出中)"的狀態

  • 4.(與第3同時)當Kubelet看到Pod標記爲退出中的時候,由於第2步中時間已經設置了,它開始pod關閉的流程

    • 4.1若是該Pod定義了一箇中止前的鉤子,其會在pod內部被調用。若是鉤子在優雅退出時間段超時仍然在運行,第二步會意一個很小的優雅時間斷被調用

    • 4.2進程被髮送TERM的信號

  • 5.(與第三步同時進行)Pod從service的列表中被刪除,不在被認爲是運行着的pod的一部分。緩慢關閉的pod能夠繼續對外服務,當負載均衡器將他們輪流移除。

  • 6.當優雅退出時間超時了,任何pod中正在運行的進程會被髮送SIGKILL信號被殺死。

  • 7.Kubelet會完成pod的刪除,將優雅退出的時間設置爲0(表示當即刪除)。pod從API中刪除,不在對客戶端可見。

默認狀況下,全部的刪除操做的優雅退出時間都在30秒之內。kubectl delete命令支持--grace-period=的選項,以運行用戶來修改默認值。0表示刪除當即執行,而且當即從API中刪除pod這樣一個新的pod會在同時被建立。在節點上,被設置了當即結束的的pod,仍然會給一個很短的優雅退出時間段,纔會開始被強制殺死。

nginx與SIGTERM

有兩種方式能夠向正在運行的Nginx進程的發送信號以徹底管理操做:使用Nginx進程的 -s 選項或者直接使用系統命令kill發送信號給master進程。使用 -s 選項時,nginx會自動查找運行中的master進程ID(master進程負責接收並處理信號,同時根據不一樣的信號,對全部工做進程完成不一樣的管理操做).

SIGINT和SIGTERM做用同樣,用於強制 Nginx進程退出;master進程接到強制退出信號時,會向全部工做進程發送強制退出信號,若是工做進程未能及時退出,master使用計時器重複發送強制信號,計時器觸發時會發送SIGALRM信號;SIGIO信號被Nginx顯式忽略;SIGCHLD信號告訴 master進程有工做進程退出,須要完成資源回收或者重啓工做進程的工做。

Nginx進程退出分爲兩種

  • master進程接到SIGQUIT信號時
    將此信號轉發給工做進程。工做進程隨後關閉監聽端口以便再也不接收新的鏈接請求,並閉空閒鏈接,等待活躍鏈接所有正常結速後,調用 ngx_worker_process_exit 退出。而 master 進程在全部工做進程都退出後,調用 ngx_master_process_exit 函數退出;

  • master進程接收到SIGTERM或者SIGINT信號時
    將信號轉發給工做進程。工 做進程直接調用 ngx_worker_process_exit 函數退出。master進程在全部工做進程都退出後,調用ngx_master_process_exit 函數退出。另外,若是工做進程未能正常退出,master進程會等待1秒後,發送SIGKILL信號強制終止工做進程。

nginx的優雅退出

-s signal      Send signal to the master process. The argument signal can be
                one of: stop, quit, reopen, reload.

                The following table shows the corresponding system signals.

                stop    SIGTERM
                quit    SIGQUIT
                reopen  SIGUSR1
                reload  SIGHUP

其中
stop — 快速關閉
quit — 優雅退出,執行完當前的請求後退出
reload — 從新加載配置文件
reopen — 從新打開日誌文件

使用kubernetes Lifecycle Hooks優雅退出nginx

kind: Deployment
metadata:
  name: nginx-demo
  namespace: scm
  labels:
    app: nginx-demo
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: nginx-demo
    spec:
      containers:
      - name: nginx-demo
        image: library/nginx-demo
        imagePullPolicy: IfNotPresent
        lifecycle:
          preStop:
            exec:
              # nginx -s quit gracefully terminate while SIGTERM triggers a quick exit
              command: ["/usr/local/openresty/nginx/sbin/nginx","-s","quit"]
        env:
          - name: PROFILE
            value: "test"
        ports:
          - name: http
            containerPort: 8080

題外

如何優雅地關閉java應用

command: ["/bin/bash", "-c", "PID=`pidof java` && kill -SIGTERM $PID && while ps -p $PID > /dev/null; do sleep 1; done;"]

doc

相關文章
相關標籤/搜索