溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Kubernetes優(yōu)雅停止Pod

發(fā)布時(shí)間:2020-07-14 07:01:51 來(lái)源:網(wǎng)絡(luò) 閱讀:433 作者:Abcdocker 欄目:系統(tǒng)運(yùn)維

原文:https://i4t.com/4424.html
Kubernetes優(yōu)雅停止Pod


首先我們先簡(jiǎn)單的分析一下"優(yōu)雅的停止Pod"

優(yōu)雅停止(Graceful shutdown)這個(gè)說(shuō)法來(lái)自于操作系統(tǒng),比如我們windows關(guān)機(jī)系統(tǒng)首先會(huì)退出軟件然后一步步到達(dá)關(guān)機(jī),而相對(duì)的就是硬終止(Hard shutdown),簡(jiǎn)單的理解就是直接拔電源

到了微服務(wù)中,網(wǎng)關(guān)會(huì)把流量分配給每個(gè)Pod節(jié)點(diǎn)上,比如我們上線更新Pod的時(shí)候

  • 如果我們直接將Pod殺死,那這部分流量就無(wú)法得到正確處理,會(huì)影響部分用戶(hù),通常來(lái)說(shuō)網(wǎng)關(guān)或者注冊(cè)中心會(huì)將我們的服務(wù)保持一個(gè)心跳,過(guò)了心跳超時(shí)之后會(huì)自動(dòng)摘除我們的服務(wù),但是有一個(gè)問(wèn)題就是超時(shí)時(shí)間可能是30秒也可能是60秒,雖然不會(huì)影響我們的系統(tǒng),但是會(huì)產(chǎn)生用戶(hù)輕微抖動(dòng)。
  • 如果我們?cè)谕V骨皥?zhí)行一條命令,通知網(wǎng)關(guān)或者注冊(cè)中心這臺(tái)主機(jī)進(jìn)行下線,那么注冊(cè)中心就會(huì)標(biāo)記這臺(tái)主機(jī)已經(jīng)下線,不進(jìn)行流量轉(zhuǎn)發(fā),用戶(hù)就不會(huì)有任何影響,這就是優(yōu)雅停止,將滾動(dòng)更新影響最小化

Pod Hook

Pod Hook是由kubelet發(fā)起的,當(dāng)容器中的進(jìn)程啟動(dòng)前或者容器中的進(jìn)程終止之前運(yùn)行,這是包含在容器的生命周期之中。我們可以同時(shí)為Pod中的所有容器都配置hook

在k8s中,理想的狀態(tài)是pod優(yōu)雅釋放,并產(chǎn)生新的Pod。但是并不是每一個(gè)Pod都會(huì)這么順利

  • Pod卡死,處理不了優(yōu)雅退出的命令或者操作
  • 優(yōu)雅退出的邏輯有BUG,陷入死循環(huán)
  • 代碼問(wèn)題,導(dǎo)致執(zhí)行的命令沒(méi)有效果

對(duì)于以上問(wèn)題,k8s的Pod終止流程中還有一個(gè)"最多可以容忍的時(shí)間",即grace period (在pod的.spec.terminationGracePeriodSeconds字段定義),這個(gè)值默認(rèn)是30秒,當(dāng)我們執(zhí)行kubectl delete的時(shí)候也可以通過(guò)--grace-period參數(shù)顯示指定一個(gè)優(yōu)雅退出時(shí)間來(lái)覆蓋Pod中的配置,如果我們配置的grace period超過(guò)時(shí)間之后,k8s就只能選擇強(qiáng)制kill Pod


Kubernetes為我們提供了兩種鉤子函數(shù):

  • PostStart :這個(gè)鉤子在容器創(chuàng)建后立即執(zhí)行。但是,并不能保證鉤子將在容器ENTRYPOINT之前運(yùn)行,因?yàn)闆](méi)有參數(shù)傳遞給處理程序。 主要用于資源部署、環(huán)境準(zhǔn)備等。不過(guò)需要注意的是如果鉤子花費(fèi)時(shí)間過(guò)長(zhǎng)以及于不能運(yùn)行或者掛起,容器將不能達(dá)到Running狀態(tài)。
  • PreStop :鉤子在容器終止前立即被調(diào)用。它是阻塞的,意味著它是同步的,所以它必須在刪除容器的調(diào)用出發(fā)之前完成。主要用于優(yōu)雅關(guān)閉應(yīng)用程序、通知其他系統(tǒng)等。如果鉤子在執(zhí)行期間掛起,Pod階段將停留在Running狀態(tài)并且不會(huì)達(dá)到failed狀態(tài)

如果PostStart或者PreStop鉤子失敗,它會(huì)殺死容器。所以我們應(yīng)該讓鉤子函數(shù)盡可能的輕量。當(dāng)然有些情況下,長(zhǎng)時(shí)間運(yùn)行命令是合理的,比如在停止容器之前預(yù)先保留狀態(tài)。

這里稍微簡(jiǎn)單說(shuō)一下Pod終止的過(guò)程

  • 用戶(hù)發(fā)送命令刪除Pod,Pod進(jìn)入Terminating狀態(tài)
  • service摘除Pod節(jié)點(diǎn)
  • 當(dāng)kubelet看到Pod已被標(biāo)記終止,開(kāi)始執(zhí)行preStop鉤子,假如preStop hook的運(yùn)行時(shí)間超過(guò)了grace period,kubelet會(huì)發(fā)送SIGTERM并等2秒
    官方文檔介紹

在Pod Hook鉤子函數(shù)中有Exec和HTTP兩種方式

  • Exec - 用于執(zhí)行一段特定的命令,不過(guò)要注意的是該命令小號(hào)的資源會(huì)被計(jì)入容器
  • HTTP - 對(duì)容器上的特定端點(diǎn)執(zhí)行HTTP請(qǐng)求

基于PostStart命令演示

首先我們先進(jìn)行演示PostStart的兩種方式

第一種Exec
我們echo一段話追加到 /tmp/message,在Pod啟動(dòng)前進(jìn)行操作

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進(jìn)行創(chuàng)建

可以通過(guò)下面查看結(jié)果,pod的目錄已經(jīng)有我們?cè)趛aml文件寫(xiě)的測(cè)試文件

[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

創(chuàng)建容器后,Kubernetes立即發(fā)送postStart事件。但是,不能保證在調(diào)用Container的入口點(diǎn)之前先調(diào)用postStart處理程序。postStart處理程序相對(duì)于Container的代碼異步運(yùn)行,但是Kubernetes對(duì)容器的管理會(huì)阻塞,直到postStart處理程序完成。在postStart處理程序完成之前,容器的狀態(tài)不會(huì)設(shè)置為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

這里就不進(jìn)行演示了,因?yàn)槿罩緯?huì)看不到這個(gè)請(qǐng)求


基于PreStop環(huán)境演示

起因:
在生產(chǎn)環(huán)境中使用spring框架,由于服務(wù)更新過(guò)程中,服務(wù)容器被直接充值,部分請(qǐng)求仍被分發(fā)到終止的容器(沒(méi)有配置鉤子,熟悉默認(rèn)環(huán)境),導(dǎo)致服務(wù)出現(xiàn)500錯(cuò)誤,這部分錯(cuò)誤請(qǐng)求數(shù)據(jù)占用比較少,因?yàn)镻od滾動(dòng)更新都是一對(duì)一。因?yàn)椴糠钟脩?hù)會(huì)產(chǎn)生服務(wù)器錯(cuò)誤的情況,考慮使用優(yōu)雅的終止方式,將錯(cuò)誤請(qǐng)求降到最低,直至滾動(dòng)更新不影響用戶(hù)

Eureka是一個(gè)基于REST的服務(wù),作為Spring Cloud服務(wù)注冊(cè)中心,用于定位服務(wù)來(lái)進(jìn)行中間層服務(wù)器的負(fù)載均衡和故障轉(zhuǎn)移。各服務(wù)啟動(dòng)時(shí),會(huì)向Eureka Server注冊(cè)自己的信息(IP、端口、服務(wù)信息等),Eureka Server會(huì)存儲(chǔ)這些信息,微服務(wù)啟動(dòng)后,會(huì)周期性(默認(rèn)30秒)的向Eureka Server發(fā)送心跳以續(xù)約自己的租期,并且可以從eureka中獲取其他微服務(wù)的地址信息,執(zhí)行相關(guān)邏輯

Kubernetes優(yōu)雅停止Pod

由于Eureka默認(rèn)的心跳檢測(cè)為30秒,當(dāng)K8S下線Pod時(shí)Eureka會(huì)有30秒的異常問(wèn)題,所以我們需要在Pod 停止前發(fā)送一條請(qǐng)求,通知Eureka進(jìn)行下線操作,這樣進(jìn)行優(yōu)雅的停止對(duì)用戶(hù)的影響做到最小

具體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'

####### 參數(shù)解釋
127.0.0.1:8080 #代表eureka地址
service-registry    #代表注冊(cè)中心
DOWN        #執(zhí)行down請(qǐng)求
sleep       #等待30秒

當(dāng)我們刪除Pod的時(shí)候就會(huì)執(zhí)行上面的命令操作,并且等待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不會(huì)馬上刪除,而是執(zhí)行Exec中的命令,并等待30秒

配置中添加了一個(gè)sleep時(shí)間,主要是作為服務(wù)停止的緩沖時(shí)間

總結(jié): Hook調(diào)用的日志沒(méi)有暴露給Pod的Event,所以只能到通過(guò)describe命令來(lái)獲取,如果是正常的操作是不會(huì)有event,如果有錯(cuò)誤可以看到FailedPostStartHook和FailedPreStopHook這種event。并且如果Hook調(diào)用出現(xiàn)錯(cuò)誤,則Pod狀態(tài)不會(huì)是Running

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI