Pod健康檢查

一、健康檢查

Pod中容器的聲明周期的兩個(gè)鉤子函數(shù), PostStart 與 PreStop,其中, PostStart 是在容器創(chuàng)建后立即執(zhí)行的,而 preStop 這個(gè)鉤子函數(shù)則是在容器終止之前執(zhí)行的,除了上面兩個(gè)鉤子函數(shù)之外,還有一項(xiàng)配置會(huì)影響到容器的生命周期,那就是健康檢查的探針。

在 <code>Kubernetes</code> 集群中,我們可以通過配置 <code>liveness probe(存活探針)</code>和 <code>readingess probe(可讀性探針)</code>來影響容器的生存周期

* kubelet 通過使用 liveness probe 來確定你的應(yīng)用程序
是否正在運(yùn)行,通俗點(diǎn)將就是是否還活著。一般來說,如果你的程序
一旦崩潰了, Kubernetes 就會(huì)立刻知道這個(gè)程序已經(jīng)終止了
,然后就會(huì)重啟這個(gè)程序。而我們的 liveness probe 的目的就
是來捕獲到當(dāng)前應(yīng)用程序還沒有終止,還沒有崩潰,如果出現(xiàn)了
這些情況,那么就重啟處于該狀態(tài)下的容器,使應(yīng)用程序在存在
 bug 的情況下依然能夠繼續(xù)運(yùn)行下去。
 
* kubelet 使用 readiness probe 來確定容器是否已經(jīng)就緒可
以接收流量過來了。這個(gè)探針通俗點(diǎn)講就是說是否準(zhǔn)備好了,現(xiàn)
在可以開始工作了。只有當(dāng) Pod 中的容器都處于就緒狀態(tài)的時(shí)候
kubelet 才會(huì)認(rèn)定該 Pod 處于就緒狀態(tài),因?yàn)橐粋€(gè) Pod 下面
可能會(huì)有多個(gè)容器。當(dāng)然 Pod 如果處于非就緒狀態(tài),那么我們
就會(huì)將他從我們的工作隊(duì)列(實(shí)際上就是我們后面需要重點(diǎn)學(xué)習(xí)的
Service)中移除出來,這樣我們的流量就不會(huì)被路由到這個(gè) Pod 里面來了。

和前面的鉤子函數(shù)一樣的,我們這兩個(gè)探針的支持兩種配置方式:

* exec:執(zhí)行一段命令
* http:檢測(cè)某個(gè) http 請(qǐng)求
* tcpSocket:使用此配置, kubelet 將嘗試在指定端口上打開容器的套接字。如果可以建立連接,容器被認(rèn)為是健康的,如果不能就認(rèn)為是失敗的。實(shí)際上就是檢查端口

接下來為大家演示下存活探針的使用方法,首先我們用 <code>exec</code> 執(zhí)行命令的方式來檢測(cè)容器的存活,如下:

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec
  labels:
    test: liveness
spec:
  containers:       //容器
  - name: liveness  //容器名字
    image: busybox      //鏡像
    args:           //args
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:  //存活檢查
      exec:
        command:    //命令
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5     // 延遲探測(cè)時(shí)間
      periodSeconds: 5          // 執(zhí)行探測(cè)頻率

這里我們需要用到一個(gè)新的屬性:<code>livenessProbe</code> ,下面通過<code>exec</code> 執(zhí)行一段命令,其中 <code>periodSeconds</code> 屬性表示讓 kubelet 每隔 5 秒執(zhí)行一次存活探針,也就是每 5秒執(zhí)行一次上面的 <code>cat/tmp/healthy</code> 命令,如果命令執(zhí)行成功了,則返回0,那么 kubelet 就會(huì)認(rèn)為當(dāng)前這個(gè)容器是存活的并且被監(jiān)控,如果返回的是非0,那么kubelet 就會(huì)把該容器殺掉然后重啟它,另外一個(gè)屬性 <code>initialDelaySeconds</code> 表示在第一次執(zhí)行探針的時(shí)候要等待 5 秒,這樣能夠確保我們的容器能夠有足夠的時(shí)間來啟動(dòng)起來。我們可以想象一下,如果你得第一次執(zhí)行探針等候的時(shí)間太短,是不是容器可能還沒正常啟動(dòng)起來,所以存活探針很可能始終都是失敗的,這樣就無限的重啟下去,所以一個(gè)合理的 <code>initiaDelaySeconds</code>非常重要。
另外我們?cè)谌萜鲉?dòng)的時(shí)候執(zhí)行了如下命令:

 /bin/sh -c "touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600"

意思就是說在容器最開始的30秒內(nèi)有一個(gè) <code>/tmp/healthy</code>文件,在這30秒內(nèi)執(zhí)行 <code>cat/tmp/heathy</code>命令都會(huì)返回一個(gè)成功的返回碼。30秒后,我們刪除這個(gè)文件,現(xiàn)在執(zhí)行 <code>cat/tmp/heathy</code> 是不是就會(huì)失敗了,這個(gè)時(shí)候就會(huì)重啟容器了。

我們創(chuàng)建下該 pod , 在30秒內(nèi),查看 pod 的 Event:

?  ~ kubectl describe pod liveness-exec

我們可以觀察到容器是正常啟動(dòng)的,在隔一會(huì),比如40秒之后,再查看 pod 的 Event ,在最下面有一條信息顯示 <code>liveness probe</code> 失敗了,容器被刪掉并重新創(chuàng)建。

然后通過 kubelet get pod liveness-exec 可以看到 RESTARTS 值加 1 了。

同樣的,我們還可以使用 <code>HTTP GET </code> 請(qǐng)求來配置我們的存活探針,我們這里使用一個(gè) liveness 鏡像來驗(yàn)證演示如下 :

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: cnych/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz  //路徑
        port: 8080  //端口
        httpHeaders:
        - name: X-Custom-Header //headers 名稱
          value: Awesome    //headers value
      initialDelaySeconds: 3     // 延遲探測(cè)時(shí)間
      periodSeconds: 3  // 執(zhí)行探測(cè)頻率

同樣的,根據(jù) periodSeconds 屬性我們可以知道 kubelet 需要每隔 3 秒執(zhí)行一次 liveness probe , 該探針將向容器中的 server 的8080端口發(fā)送一個(gè) HTTP GET 請(qǐng)求,如果 server 的 /heathyz 路徑的 handler 返回一個(gè)成功的返回碼,kubelet 就會(huì)認(rèn)定該容器是活著的并且很健康,如果返回失敗的返回碼, kubelet 將殺掉該容器并重啟它。 initiaDelaySeconds 指定 kubelet 在該執(zhí)行第一次探測(cè)之前需要等待3秒鐘。

通常來說,任何大于 200 小于 400 的返回碼都會(huì)認(rèn)定是成功的返回碼。其他返回碼都會(huì)被認(rèn)為是失敗的返回碼。

我們可以來查看下面的 healthy 的實(shí)現(xiàn):

http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
    duration := time.Now().Sub(started)
    if duration.Seconds() > 10 {
        w.WriteHeader(500)
        w.Write([]byte(fmt.Sprintf("error: %v", duration.Seconds())))
    } else {
        w.WriteHeader(200)
        w.Write([]byte("ok"))
    }
})

大概意思就是最開始前10秒返回的狀態(tài)碼是 200 ,10s 過后就返回 500 的 status_code 了。所以當(dāng)容器啟動(dòng)3s 后,kubelet 開始執(zhí)行健康檢查。第一次檢測(cè)會(huì)成功,因?yàn)槭窃?10s 之內(nèi),但是 10 秒之后,健康檢查將失敗,因?yàn)楝F(xiàn)在返回的是一個(gè)錯(cuò)誤的狀態(tài)碼了,所以 kubelet 將會(huì)殺掉和重啟容器,

同意的我們來創(chuàng)建該P(yáng)od 測(cè)試下效果, 10 秒后,查看 Pod的 Event, 確認(rèn) liveness probe 失敗并重啟了容器。

?  ~ kubectl describe pod liveness-http

然后我們來通過端口的方式來配置存活探針,使用此配置, kubelet 將嘗試在指定端口上打開容器的套接字。如果可以建立連接,容器被認(rèn)為是健康的,如果不能就是失敗的。

apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: cnych/goproxy
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

我們可以看到,TCP 檢查的配置與 HTTP 檢查非常相似,只是將httpGet替換成了tcpSocket。 而且我們同時(shí)使用了readiness probe和liveness probe兩種探針。 容器啟動(dòng)后5秒后,kubelet將發(fā)送第一個(gè)readiness probe(可讀性探針)。 該探針會(huì)去連接容器的8080端,如果連接成功,則該 Pod 將被標(biāo)記為就緒狀態(tài)。然后Kubelet將每隔10秒鐘執(zhí)行一次該檢查。

除了readiness probe之外,該配置還包括liveness probe。 容器啟動(dòng)15秒后,kubelet將運(yùn)行第一個(gè) liveness probe。 就像readiness probe一樣,這將嘗試去連接到容器的8080端口。如果liveness probe失敗,容器將重新啟動(dòng)。

有的時(shí)候,應(yīng)用程序可能暫時(shí)無法對(duì)外提供服務(wù),例如,應(yīng)用程序可能需要在啟動(dòng)期間加載大量數(shù)據(jù)或配置文件。 在這種情況下,您不想殺死應(yīng)用程序,也不想對(duì)外提供服務(wù)。 那么這個(gè)時(shí)候我們就可以使用readiness probe來檢測(cè)和減輕這些情況。 Pod中的容器可以報(bào)告自己還沒有準(zhǔn)備,不能處理Kubernetes服務(wù)發(fā)送過來的流量。

從上面的YAML文件我們可以看出readiness probe的配置跟liveness probe很像,基本上一致的。唯一的不同是使用readinessProbe而不是livenessProbe。兩者如果同時(shí)使用的話就可以確保流量不會(huì)到達(dá)還未準(zhǔn)備好的容器,準(zhǔn)備好過后,如果應(yīng)用程序出現(xiàn)了錯(cuò)誤,則會(huì)重新啟動(dòng)容器。

另外除了上面的initialDelaySeconds和periodSeconds屬性外,探針還可以配置如下幾個(gè)參數(shù):

* timeoutSeconds:探測(cè)超時(shí)時(shí)間,默認(rèn)1秒,最小1秒。
* successThreshold:探測(cè)失敗后,最少連續(xù)探測(cè)成功多少次才被認(rèn)定為成功。默認(rèn)是 1,但是如果是`liveness`則必須是 1。最小值是 1。
* failureThreshold:探測(cè)成功后,最少連續(xù)探測(cè)失敗多少次才被認(rèn)定為失敗。默認(rèn)是 3,最小值是 1。

這就是liveness probe(存活探針)和readiness probe(可讀性探針)的使用方法。在Pod的生命周期當(dāng)中,我們已經(jīng)學(xué)習(xí)了容器生命周期中的鉤子函數(shù)和探針檢測(cè),下節(jié)課給大家講解Pod層面生命周期的一個(gè)階段:初始化容器。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容