原文:https://i4t.com/4424.html
html
首先咱們先簡單的分析一下"優雅的中止Pod"nginx
優雅中止(Graceful shutdown)這個說法來自於操做系統,好比咱們windows關機系統首先會退出軟件而後一步步到達關機,而相對的就是硬終止(Hard shutdown),簡單的理解就是直接拔電源spring
到了微服務中,網關會把流量分配給每一個Pod節點上,好比咱們上線更新Pod的時候docker
Pod Hook是由kubelet發起的,當容器中的進程啓動前或者容器中的進程終止以前運行,這是包含在容器的生命週期之中。咱們能夠同時爲Pod中的全部容器都配置hookjson
在k8s中,理想的狀態是pod優雅釋放,併產生新的Pod。可是並非每個Pod都會這麼順利windows
對於以上問題,k8s的Pod終止流程中還有一個"最多能夠容忍的時間",即grace period (在pod的.spec.terminationGracePeriodSeconds
字段定義),這個值默認是30秒,當咱們執行kubectl delete
的時候也能夠經過--grace-period
參數顯示指定一個優雅退出時間來覆蓋Pod中的配置,若是咱們配置的grace period超過期間以後,k8s就只能選擇強制kill Podapi
Kubernetes爲咱們提供了兩種鉤子函數:bash
若是PostStart或者PreStop鉤子失敗,它會殺死容器。因此咱們應該讓鉤子函數儘量的輕量。固然有些狀況下,長時間運行命令是合理的,好比在中止容器以前預先保留狀態。服務器
這裏稍微簡單說一下Pod終止的過程app
在Pod Hook鉤子函數中有Exec和HTTP兩種方式
首先咱們先進行演示PostStart的兩種方式
第一種Exec
咱們echo一段話追加到 /tmp/message,在Pod啓動前進行操做
cat >>exec_test.yaml<<EOF apiVersion: v1 kind: Pod metadata: name: abcdocker labels: name: abcdocker spec: containers: - name: abcdocker image: nginx ports: - containerPort: 80 lifecycle: postStart: exec: command: - bash - -c - 'echo "https://i4t.com" > /tmp/message' EOF
使用kubectl apply -f exec_test.yaml
進行建立
能夠經過下面查看結果,pod的目錄已經有咱們在yaml文件寫的測試文件
[root@abcdocker yaml]# kubectl get pod NAME READY STATUS RESTARTS AGE abcdocker 1/1 Running 0 37s [root@abcdocker yaml]# kubectl exec -it -n default abcdocker /bin/bash root@abcdocker:/# cat /tmp/message https://i4t.com root@abcdocker:/# root@abcdocker:/# exit
建立容器後,Kubernetes當即發送postStart事件。可是,不能保證在調用Container的入口點以前先調用postStart處理程序。postStart處理程序相對於Container的代碼異步運行,可是Kubernetes對容器的管理會阻塞,直到postStart處理程序完成。在postStart處理程序完成以前,容器的狀態不會設置爲RUNNING。
第二種HTTP方式
使用HttpGet配置Host、Path、Port
apiVersion: v1 kind: Pod metadata: name: abcdocker labels: name: abcdocker spec: containers: - name: abcdocker image: nginx ports: - containerPort: 80 lifecycle: postStart: httpGet: host: i4t.com path: index.html port: 80
這裏就不進行演示了,由於日誌會看不到這個請求
原由:
在生產環境中使用spring框架,因爲服務更新過程當中,服務容器被直接充值,部分請求仍被分發到終止的容器(沒有配置鉤子,熟悉默認環境),致使服務出現500錯誤,這部分錯誤請求數據佔用比較少,由於Pod滾動更新都是一對一。由於部分用戶會產生服務器錯誤的狀況,考慮使用優雅的終止方式,將錯誤請求降到最低,直至滾動更新不影響用戶
Eureka是一個基於REST的服務,做爲Spring Cloud服務註冊中心,用於定位服務來進行中間層服務器的負載均衡和故障轉移。各服務啓動時,會向Eureka Server註冊本身的信息(IP、端口、服務信息等),Eureka Server會存儲這些信息,微服務啓動後,會週期性(默認30秒)的向Eureka Server發送心跳以續約本身的租期,而且能夠從eureka中獲取其餘微服務的地址信息,執行相關邏輯
因爲Eureka默認的心跳檢測爲30秒,當K8S下線Pod時Eureka會有30秒的異常問題,因此咱們須要在Pod 中止前發送一條請求,通知Eureka進行下線操做,這樣進行優雅的中止對用戶的影響作到最小
具體yaml以下
apiVersion: v1 kind: Pod metadata: name: abcdocker labels: name: abcdocker spec: containers: - name: abcdocker image: nginx ports: - containerPort: 80 lifecycle: preStop: exec: command: - bash - -c - 'curl -X POST --data DOWN http://127.0.0.1:8080/service-registry/instance-status -H "Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8";sleep 30' ####### 參數解釋 127.0.0.1:8080 #表明eureka地址 service-registry #表明註冊中心 DOWN #執行down請求 sleep #等待30秒
當咱們刪除Pod的時候就會執行上面的命令操做,而且等待30秒
[root@yzsjhl82-135 yaml]# kubectl get pod NAME READY STATUS RESTARTS AGE abcdocker 1/1 Running 0 2m16s [root@yzsjhl82-135 yaml]# kubectl delete pod abcdocker pod "abcdocker" deleted #此刻Pod不會立刻刪除,而是執行Exec中的命令,並等待30秒
配置中添加了一個sleep時間,主要是做爲服務中止的緩衝時間
總結: Hook調用的日誌沒有暴露給Pod的Event,因此只能到經過describe
命令來獲取,若是是正常的操做是不會有event,若是有錯誤能夠看到FailedPostStartHook和FailedPreStopHook這種event。而且若是Hook調用出現錯誤,則Pod狀態不會是Running