您好,登錄后才能下訂單哦!
原文:https://i4t.com/4424.html
首先我們先簡單的分析一下"優雅的停止Pod"
優雅停止(Graceful shutdown)這個說法來自于操作系統,比如我們windows關機系統首先會退出軟件然后一步步到達關機,而相對的就是硬終止(Hard shutdown),簡單的理解就是直接拔電源
到了微服務中,網關會把流量分配給每個Pod節點上,比如我們上線更新Pod的時候
Pod Hook是由kubelet發起的,當容器中的進程啟動前或者容器中的進程終止之前運行,這是包含在容器的生命周期之中。我們可以同時為Pod中的所有容器都配置hook
在k8s中,理想的狀態是pod優雅釋放,并產生新的Pod。但是并不是每一個Pod都會這么順利
對于以上問題,k8s的Pod終止流程中還有一個"最多可以容忍的時間",即grace period (在pod的.spec.terminationGracePeriodSeconds
字段定義),這個值默認是30秒,當我們執行kubectl delete
的時候也可以通過--grace-period
參數顯示指定一個優雅退出時間來覆蓋Pod中的配置,如果我們配置的grace period超過時間之后,k8s就只能選擇強制kill Pod
Kubernetes為我們提供了兩種鉤子函數:
如果PostStart或者PreStop鉤子失敗,它會殺死容器。所以我們應該讓鉤子函數盡可能的輕量。當然有些情況下,長時間運行命令是合理的,比如在停止容器之前預先保留狀態。
這里稍微簡單說一下Pod終止的過程
在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
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。