K8S 中的健康檢查機(jī)制

image

概述

健康檢查(Health Check)用于檢測(cè)您的應(yīng)用實(shí)例是否正常工作,是保障業(yè)務(wù)可用性的一種傳統(tǒng)機(jī)制,一般用于負(fù)載均衡下的業(yè)務(wù),如果實(shí)例的狀態(tài)不符合預(yù)期,將會(huì)把該實(shí)例“摘除”,不承擔(dān)業(yè)務(wù)流量。

Kubernetes中的健康檢查使用存活性探針(liveness probes)和就緒性探針(readiness probes)來(lái)實(shí)現(xiàn),service即為負(fù)載均衡,k8s保證 service 后面的 pod 都可用,是k8s中自愈能力的主要手段,基于這兩種探測(cè)機(jī)制,可以實(shí)現(xiàn)如下需求:

  • 異常實(shí)例自動(dòng)剔除,并重啟新實(shí)例
  • 多種類(lèi)型探針檢測(cè),保證異常pod不接入流量
  • 不停機(jī)部署,更安全的滾動(dòng)升級(jí)

目前支持的探測(cè)方式包括:

  • HTTP
  • TCP
  • Exec命令

k8s 中的 示例配置如下:

image

探針類(lèi)型

默認(rèn)機(jī)制:

如果把 k8s 對(duì) pod 的crash 狀態(tài)判斷也能稱(chēng)之為“健康檢查”的話,那算是默認(rèn)的健康檢查機(jī)制了,

每個(gè)容器啟動(dòng)時(shí)都會(huì)執(zhí)行一個(gè)主進(jìn)程,如果進(jìn)程退出返回碼不是0,則認(rèn)為容器異常,即pod異常,k8s 會(huì)根據(jù)restartPolicy策略選擇是否殺掉 pod,再重新啟動(dòng)一個(gè)。

restartPolicy分為三種:

  • Always:當(dāng)容器終止退出后,總是重啟容器,默認(rèn)策略。
  • Onfailure:當(dāng)容器異常退出(退出碼非0)時(shí),才重啟容器。
  • Never:當(dāng)容器終止退出時(shí),才不重啟容器。

存活探針

上面的默認(rèn)機(jī)制中,容器進(jìn)程返回值非0則認(rèn)為容器發(fā)生故障,需要重啟。但很多情況下服務(wù)出現(xiàn)問(wèn)題,進(jìn)程卻沒(méi)有退出,如系統(tǒng)超載 5xx 錯(cuò)誤,資源死鎖等。這種情況下就需要健康檢查機(jī)制出場(chǎng)了

存活探針(Liveness probe):讓Kubernetes知道你的應(yīng)用程序是否健康,如果你的應(yīng)用程序不健康,Kubernetes將刪除Pod并啟動(dòng)一個(gè)新的替換它。這里的“健康”不再是進(jìn)程狀態(tài),而是用戶(hù)自定義探測(cè)方式:HTTP、TCP、Exec

舉例說(shuō)明:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness
spec:
  restartPolicy: OnFailure
  containers:
  - name: liveness
    image: busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -fr /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 10
      periodSeconds: 5

啟動(dòng)進(jìn)程首先創(chuàng)建文件 /tmp/healthy,30 秒后刪除,在我們的設(shè)定中,如果 /tmp/healthy 文件存在,則認(rèn)為容器處于正常狀態(tài),反正則發(fā)生故障。

livenessProbe 部分定義如何執(zhí)行 Liveness 探測(cè):

  1. 探測(cè)的方法是:通過(guò) cat 命令檢查 /tmp/healthy 文件是否存在。如果命令執(zhí)行成功,返回值為0,Kubernetes 則認(rèn)為本次 Liveness 探測(cè)成功;如果命令返回值非0,本次 Liveness 探測(cè)失敗。

  2. initialDelaySeconds: 10,指定容器啟動(dòng) 10s 之后開(kāi)始執(zhí)行 Liveness 探測(cè),我們一般會(huì)根據(jù)應(yīng)用啟動(dòng)的準(zhǔn)備時(shí)間來(lái)設(shè)置。比如某個(gè)應(yīng)用正常啟動(dòng)要花 30 秒,那么 initialDelaySeconds 的值就應(yīng)該大于 30。

  3. periodSeconds: 5, 指定每 5 秒執(zhí)行一次 Liveness 探測(cè)。Kubernetes 如果連續(xù)執(zhí)行 3 次 Liveness 探測(cè)均失敗,則會(huì)殺掉并重啟容器。3次是可以配置的,參數(shù)為failureThreshold,含義后面解釋

使用上面的 yaml 創(chuàng)建 pod:

image

剛開(kāi)始的 30s,健康檢查能通過(guò)。

image

此時(shí)的events 顯示正常

image

30s 后,日志會(huì)顯示 /tmp/healthy 已經(jīng)不存在,Liveness 探測(cè)失敗。再過(guò)幾十秒,幾次探測(cè)都失敗后,容器會(huì)被重啟。events 中可以看到重試 了 3次探測(cè),每次間隔 10s,單次探測(cè)的超時(shí)時(shí)間為 1s。

image

liveness 的配置來(lái)自 v1中的Probe資源,所有屬性含義如下:

  • httpGet:對(duì)應(yīng)HTTPGetAction對(duì)象,屬性包括:host、httpHeaders、path、port、scheme
  • initialDelaySeconds:容器啟動(dòng)后開(kāi)始探測(cè)之前需要等多少秒,如應(yīng)用啟動(dòng)一般30s的話,就設(shè)置為 30s
  • periodSeconds:執(zhí)行探測(cè)的頻率(多少秒執(zhí)行一次)。默認(rèn)為10秒。最小值為1。
  • successThreshold:探針失敗后,最少連續(xù)成功多少次才視為成功。默認(rèn)值為1。最小值為1。
  • failureThreshold:最少連續(xù)多少次失敗才視為失敗。默認(rèn)值為3。最小值為1。
  • timeoutSeconds:探測(cè)的超時(shí)時(shí)間,默認(rèn) 1s,最小 1s
  • tcpSocket:對(duì)應(yīng)TCPSocketAction對(duì)象,TCPSocket指定端口。尚不支持TCP hook
  • exec:對(duì)應(yīng)ExecAction對(duì)象,需要執(zhí)行的內(nèi)容

動(dòng)圖說(shuō)明:

https://storage.googleapis.com/gweb-cloudblog-publish/original_images/google-kubernetes-probe-livenessae14.GIF

探針執(zhí)行方式

HTTP

HTTP探針可能是最常見(jiàn)的自定義Liveness探針類(lèi)型。 即使您的應(yīng)用程序不是HTTP服務(wù),您也可以在應(yīng)用程序內(nèi)創(chuàng)建輕量級(jí)HTTP服務(wù)以響應(yīng)Liveness探針。 Kubernetes去訪問(wèn)一個(gè)路徑,如果它得到的是200或300范圍內(nèi)的HTTP響應(yīng),它會(huì)將應(yīng)用程序標(biāo)記為健康。 否則它被標(biāo)記為不健康。

httpGet配置項(xiàng):

  • host:連接的主機(jī)名,默認(rèn)連接到pod的IP。你可能想在http header中設(shè)置"Host"而不是使用IP。
  • scheme:連接使用的schema,默認(rèn)HTTP。
  • path: 訪問(wèn)的HTTP server的path。
  • httpHeaders:自定義請(qǐng)求的header。HTTP運(yùn)行重復(fù)的header。
  • port:訪問(wèn)的容器的端口名字或者端口號(hào)。端口號(hào)必須介于1和65535之間。
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-http
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/liveness
    args:
    - /server
    livenessProbe:
      httpGet:
        path: /healthz
        port: 8080
        httpHeaders:
        - name: Custom-Header
          value: Awesome
      initialDelaySeconds: 3
      periodSeconds: 3

Exec

對(duì)于Exec探針,Kubernetes則只是在容器內(nèi)運(yùn)行命令。 如果命令以退出代碼0返回,則容器標(biāo)記為健康。 否則,它被標(biāo)記為不健康。 當(dāng)您不能或不想運(yùn)行HTTP服務(wù)時(shí),此類(lèi)型的探針則很有用,但是必須是運(yùn)行可以檢查您的應(yīng)用程序是否健康的命令。

Exec 的配置項(xiàng)(exec):

  • command:需要執(zhí)行的命令,需要符合命令的格式
apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness
  name: liveness-exec
spec:
  containers:
  - name: liveness
    image: k8s.gcr.io/busybox
    args:
    - /bin/sh
    - -c
    - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600
    livenessProbe:
      exec:
        command:
        - cat
        - /tmp/healthy
      initialDelaySeconds: 5
      periodSeconds: 5

TCP

最后一種類(lèi)型的探針是TCP探針,Kubernetes嘗試在指定端口上建立TCP連接。 如果它可以建立連接,則容器被認(rèn)為是健康的;否則被認(rèn)為是不健康的。

如果您有HTTP探針或Command探針不能正常工作的情況,TCP探測(cè)器會(huì)派上用場(chǎng)。 例如,gRPC或FTP服務(wù)是此類(lèi)探測(cè)的主要候選者。

TCP 的配置項(xiàng)(tcpSocket):

  • host:探測(cè)的主機(jī),默認(rèn)為本pod ip
  • port:端口,1到65535
apiVersion: v1
kind: Pod
metadata:
  name: goproxy
  labels:
    app: goproxy
spec:
  containers:
  - name: goproxy
    image: k8s.gcr.io/goproxy:0.1
    ports:
    - containerPort: 8080
    readinessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 5
      periodSeconds: 10
    livenessProbe:
      tcpSocket:
        port: 8080
      initialDelaySeconds: 15
      periodSeconds: 20

就緒探針

就緒探針(Readiness probe):讓Kubernetes知道您的應(yīng)用是否準(zhǔn)備好其流量服務(wù)。 Kubernetes確保Readiness探針檢測(cè)通過(guò),然后允許服務(wù)將流量發(fā)送到Pod。 如果Readiness探針開(kāi)始失敗,Kubernetes將停止向該容器發(fā)送流量,直到它通過(guò)。 判斷容器是否處于可用Ready狀態(tài), 達(dá)到ready狀態(tài)表示pod可以接受請(qǐng)求, 如果不健康, 從service的后端endpoint列表中把pod隔離出去

用戶(hù)通過(guò) Liveness 探測(cè)可以告訴 Kubernetes 什么時(shí)候通過(guò)重啟容器實(shí)現(xiàn)自愈;而就緒探針Readiness則是告訴 Kubernetes 什么時(shí)候可以將容器加入到 Service 負(fù)載均衡中,對(duì)外提供服務(wù)。

Readiness 探測(cè)的配置語(yǔ)法與 Liveness 探測(cè)完全一樣,這里不再贅述。

如果連續(xù) n 次 Readiness 探測(cè)均失敗后,READY被設(shè)置為不可用。

status 為 running,但是 ready 數(shù)為 0/1

動(dòng)圖示例:

https://storage.googleapis.com/gweb-cloudblog-publish/original_images/google-kubernetes-probe-readiness6ktf.GIF

兩種探針對(duì)比

  1. Liveness 探測(cè)和 Readiness 探測(cè)是兩種 Health Check 機(jī)制,如果不特意配置,Kubernetes 將對(duì)兩種探測(cè)采取相同的默認(rèn)行為,即通過(guò)判斷容器啟動(dòng)進(jìn)程的返回值是否為零來(lái)判斷探測(cè)是否成功。

  2. 兩種探測(cè)的配置方法完全一樣,支持的配置參數(shù)也一樣。不同之處在于探測(cè)失敗后的行為:Liveness 探測(cè)是重啟容器;Readiness 探測(cè)則是將容器設(shè)置為不可用,不接收 Service 轉(zhuǎn)發(fā)的請(qǐng)求。

  3. Liveness 探測(cè)和 Readiness 探測(cè)是獨(dú)立執(zhí)行的,二者之間沒(méi)有依賴(lài),所以可以單獨(dú)使用,也可以同時(shí)使用。

  4. 用 Liveness 探測(cè)判斷容器是否需要重啟以實(shí)現(xiàn)自愈;用 Readiness 探測(cè)判斷容器是否已經(jīng)準(zhǔn)備好對(duì)外提供服務(wù)。Readiness可用于指定容器啟動(dòng)后,判斷容器各服務(wù)是否已正常啟動(dòng)(如啟動(dòng)腳本執(zhí)行后寫(xiě)指定內(nèi)容至特定文件)

使用場(chǎng)景

擴(kuò)縮容

對(duì)于生產(chǎn)環(huán)境中重要的應(yīng)用都建議配置 Health Check,保證處理客戶(hù)請(qǐng)求的容器都是準(zhǔn)備就緒的 Service backend。如果 Liveness不通過(guò),則應(yīng)該縮掉異常 pod,重新啟動(dòng)新 pod

示例:

對(duì)于 http://[container_ip]:8080/healthy,應(yīng)用則可以實(shí)現(xiàn)自己的判斷邏輯,比如檢查所依賴(lài)的數(shù)據(jù)庫(kù)是否就緒,示例代碼如下:

image

健康檢查的步驟為:

  1. 容器啟動(dòng) 10 秒之后開(kāi)始探測(cè)。
  2. 如果 http://[container_ip]:8080/healthy 返回代碼不是 200-400,表示容器沒(méi)有就緒,不接收 Service web-svc 的請(qǐng)求。
  3. 每隔 5 秒再探測(cè)一次。
  4. 直到返回代碼為 200-400,表明容器已經(jīng)就緒,然后將其加入到 web-svc 的負(fù)責(zé)均衡中,開(kāi)始處理客戶(hù)請(qǐng)求。
  5. 探測(cè)會(huì)繼續(xù)以 5 秒的間隔執(zhí)行,如果連續(xù)發(fā)生 3 次失敗,容器又會(huì)從負(fù)載均衡中移除,直到下次探測(cè)成功重新加入。
image

滾動(dòng)更新

現(xiàn)有一個(gè)正常運(yùn)行的多副本應(yīng)用,接下來(lái)對(duì)應(yīng)用進(jìn)行更新(比如使用更高版本的 image),Kubernetes 會(huì)啟動(dòng)新副本,然后發(fā)生了如下事件:

  1. 正常情況下新副本需要 10 秒鐘完成準(zhǔn)備工作,在此之前無(wú)法響應(yīng)業(yè)務(wù)請(qǐng)求。
  2. 但由于人為配置錯(cuò)誤,副本始終無(wú)法完成準(zhǔn)備工作(比如無(wú)法連接后端數(shù)據(jù)庫(kù))。

如果沒(méi)有配置健康檢查,則有問(wèn)題的新副本將替換老副本,導(dǎo)致集群服務(wù)異常。

如果正確配置了 Health Check,新副本只有通過(guò)了 Readiness 探測(cè),才會(huì)被添加到 Service;如果沒(méi)有通過(guò)探測(cè),現(xiàn)有副本不會(huì)被全部替換,業(yè)務(wù)仍然正常進(jìn)行。

實(shí)現(xiàn)原理

liveness 和 readiness 的探測(cè)都是由kubelet執(zhí)行。

exec方式

func (pb *prober) runProbe(p *v1.Probe, pod *v1.Pod, status v1.PodStatus, container v1.Container, containerID kubecontainer.ContainerID) (probe.Result, string, error) {
.....        
        command := kubecontainer.ExpandContainerCommandOnlyStatic(p.Exec.Command, container.Env)
        return pb.exec.Probe(pb.newExecInContainer(container, containerID, command, timeout))
......
        
func (pb *prober) newExecInContainer(container v1.Container, containerID kubecontainer.ContainerID, cmd []string, timeout time.Duration) exec.Cmd {
    return execInContainer{func() ([]byte, error) {
        return pb.runner.RunInContainer(containerID, cmd, timeout)
    }}
}
        
......
func (m *kubeGenericRuntimeManager) RunInContainer(id kubecontainer.ContainerID, cmd []string, timeout time.Duration) ([]byte, error) {
    stdout, stderr, err := m.runtimeService.ExecSync(id.ID, cmd, 0)
    return append(stdout, stderr...), err
}

由kubelet,通過(guò)CRI接口的ExecSync接口,在對(duì)應(yīng)容器內(nèi)執(zhí)行拼裝好的cmd命令。獲取返回值。

func (pr execProber) Probe(e exec.Cmd) (probe.Result, string, error) {
    data, err := e.CombinedOutput()
    glog.V(4).Infof("Exec probe response: %q", string(data))
    if err != nil {
        exit, ok := err.(exec.ExitError)
        if ok {
            if exit.ExitStatus() == 0 {
                return probe.Success, string(data), nil
            } else {
                return probe.Failure, string(data), nil
            }
        }
        return probe.Unknown, "", err
    }
    return probe.Success, string(data), nil
}

kubelet是根據(jù)執(zhí)行命令的退出碼來(lái)決定是否探測(cè)成功。當(dāng)執(zhí)行命令的退出碼為0時(shí),認(rèn)為執(zhí)行成功,否則為執(zhí)行失敗。如果執(zhí)行超時(shí),則狀態(tài)為Unknown。

http探測(cè)

func DoHTTPProbe(url *url.URL, headers http.Header, client HTTPGetInterface) (probe.Result, string, error) {
    req, err := http.NewRequest("GET", url.String(), nil)
    ......
    if res.StatusCode >= http.StatusOK && res.StatusCode < http.StatusBadRequest {
        glog.V(4).Infof("Probe succeeded for %s, Response: %v", url.String(), *res)
        return probe.Success, body, nil
    }
    ......

http探測(cè)是通過(guò)kubelet請(qǐng)求容器的指定url,并根據(jù)response來(lái)進(jìn)行判斷。 當(dāng)返回的狀態(tài)碼在200到400(不含400)之間時(shí),也就是狀態(tài)碼為2xx和3xx,認(rèn)為探測(cè)成功。否則認(rèn)為失敗。

tcp探測(cè)

func DoTCPProbe(addr string, timeout time.Duration) (probe.Result, string, error) {
    conn, err := net.DialTimeout("tcp", addr, timeout)
    if err != nil {
        // Convert errors to failures to handle timeouts.
        return probe.Failure, err.Error(), nil
    }
    err = conn.Close()
    if err != nil {
        glog.Errorf("Unexpected error closing TCP probe socket: %v (%#v)", err, err)
    }
    return probe.Success, "", nil
}

tcp探測(cè)是通過(guò)探測(cè)指定的端口。如果可以連接,則認(rèn)為探測(cè)成功,否則認(rèn)為失敗。

其他

執(zhí)行命令探測(cè)失敗的原因主要可能是容器未成功啟動(dòng),或者執(zhí)行命令失敗。當(dāng)然也可能docker或者docker-shim存在故障。

由于http和tcp都是從kubelet自node節(jié)點(diǎn)上發(fā)起的,向容器的ip進(jìn)行探測(cè)。 所以探測(cè)失敗的原因除了應(yīng)用容器的問(wèn)題外,還可能是從node到容器ip的網(wǎng)絡(luò)不通。

readiness檢查結(jié)果會(huì)通過(guò)SetContainerReadiness函數(shù),設(shè)置到pod的status中,從而更新pod的ready condition。

liveness和readiness除了最終的作用不同,另外一個(gè)很大的區(qū)別是它們的初始值不同。

 switch probeType {
    case readiness:
        w.spec = container.ReadinessProbe
        w.resultsManager = m.readinessManager
        w.initialValue = results.Failure
    case liveness:
        w.spec = container.LivenessProbe
        w.resultsManager = m.livenessManager
        w.initialValue = results.Success
    }

liveness的初始值為成功。這樣防止在應(yīng)用還沒(méi)有成功啟動(dòng)前,就被誤殺。如果在規(guī)定時(shí)間內(nèi)還未成功啟動(dòng),才將其設(shè)置為失敗,從而觸發(fā)容器重建。

而readiness的初始值為失敗。這樣防止應(yīng)用還沒(méi)有成功啟動(dòng)前就向應(yīng)用進(jìn)行流量的導(dǎo)入。如果在規(guī)定時(shí)間內(nèi)啟動(dòng)成功,才將其設(shè)置為成功,從而將流量向應(yīng)用導(dǎo)入。

liveness與readiness二者作用不能相互替代。

例如只配置了liveness,那么在容器啟動(dòng),應(yīng)用還沒(méi)有成功就緒之前,這個(gè)時(shí)候pod是ready的(因?yàn)槿萜鞒晒?dòng)了)。那么流量就會(huì)被引入到容器的應(yīng)用中,可能會(huì)導(dǎo)致請(qǐng)求失敗。雖然在liveness檢查失敗后,重啟容器,此時(shí)pod的ready的condition會(huì)變?yōu)閒alse。但是前面會(huì)有一些流量因?yàn)殄e(cuò)誤狀態(tài)導(dǎo)入。

當(dāng)然只配置了readiness是無(wú)法觸發(fā)容器重啟的。

因?yàn)槎叩淖饔貌煌?,在?shí)際使用中,可以根據(jù)實(shí)際的需求將二者進(jìn)行配合使用。

新探針:?jiǎn)?dòng)探針

設(shè)計(jì)文檔:[https://github.com/kubernetes/enhancements/blob/master/keps/sig-node/20190221-livenessprobe-holdoff.md]

目的:

對(duì)于慢啟動(dòng)容器來(lái)說(shuō),現(xiàn)有的健康檢查機(jī)制不太好用

慢啟動(dòng)容器:指需要大量時(shí)間(一到幾分鐘)啟動(dòng)的容器。啟動(dòng)緩慢的原因可能有多種:

  • 長(zhǎng)時(shí)間的數(shù)據(jù)初始化:只有第一次啟動(dòng)會(huì)花費(fèi)很多時(shí)間
  • 負(fù)載很高:每次啟動(dòng)都花費(fèi)很多時(shí)間
  • 節(jié)點(diǎn)資源不足/過(guò)載:即容器啟動(dòng)時(shí)間取決于外部因素

這種容器的主要問(wèn)題在于,在livenessProbe失敗之前,應(yīng)該給它們足夠的時(shí)間來(lái)啟動(dòng)它們。對(duì)于這種問(wèn)題,現(xiàn)有的機(jī)制的處理方式為:

  • 方法一:livenessProbe中把延遲初始時(shí)間initialDelaySeconds設(shè)置的很長(zhǎng),以允許容器啟動(dòng)(即initialDelaySeconds大于平均啟動(dòng)時(shí)間)。雖然這樣可以確保livenessProbe不會(huì)檢測(cè)失敗,但是不知道initialDelaySeconds應(yīng)該配置為多少,啟動(dòng)時(shí)間不是一個(gè)固定值。另外,因?yàn)閘ivenessProbe在啟動(dòng)過(guò)程還沒(méi)運(yùn)行,因此pod 得不到反饋,events 看不到內(nèi)容,如果你initialDelaySeconds是 10 分鐘,那這 10 分鐘內(nèi)你不知道在發(fā)生什么。
  • 方法二:增加livenessProbe的失敗次數(shù)。即failureThreshold*periodSeconds的乘積足夠大,簡(jiǎn)單粗暴,同時(shí)容器在初次成功啟動(dòng)后,就算死鎖或以其他方式掛起,livenessProbe也會(huì)不斷探測(cè)

方法二可以解決這個(gè)問(wèn)題,但不夠優(yōu)雅。

因?yàn)閘ivenessProbe的設(shè)計(jì)是為了在 pod 啟動(dòng)成功后進(jìn)行健康探測(cè),最好前提是 pod 已經(jīng)啟動(dòng)成功,否則啟動(dòng)階段的多次失敗是沒(méi)有意義的,因此官方提出了一種新的探針:即startupProbe,startupProbe并不是一種新的數(shù)據(jù)結(jié)構(gòu),他完全復(fù)用了livenessProbe,只是名字改了下,多了一種概念,關(guān)于這個(gè) probe 的提議討論可以參考issue

使用方式:startup-probes

ports:
- name: liveness-port
  containerPort: 8080
  hostPort: 8080

livenessProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 1
  periodSeconds: 10

startupProbe:
  httpGet:
    path: /healthz
    port: liveness-port
  failureThreshold: 30
  periodSeconds: 10

這個(gè)配置的含義是:

startupProbe首先檢測(cè),該應(yīng)用程序最多有5分鐘(30 * 10 = 300s)完成啟動(dòng)。一旦startupProbe成功一次,livenessProbe將接管,以對(duì)后續(xù)運(yùn)行過(guò)程中容器死鎖提供快速響應(yīng)。如果startupProbe從未成功,則容器將在300秒后被殺死。

k8s 1.16 才開(kāi)始支持startupProbe這個(gè)特性

最佳實(shí)踐

上述的擴(kuò)縮容和滾動(dòng)升級(jí)場(chǎng)景都需要用戶(hù)對(duì)應(yīng)用的健康檢查足夠了解,并且配置合適的策略。主要工作是:

  1. 給用戶(hù)程序開(kāi)發(fā)一個(gè)/healthy 接口,來(lái)獲取世界可用狀態(tài)(僅僅是 http服務(wù))
  2. 定義合理的健康檢查組合

注意事項(xiàng):

  • periodSeconds探測(cè)周期不能太短,否則會(huì)發(fā)送很多請(qǐng)求,也不能太長(zhǎng),否則會(huì)導(dǎo)致發(fā)現(xiàn)不了異常 pod
  • 合理配置failureThreshold和successThreshold,否則會(huì)導(dǎo)致在 ready 和 not ready 直接反復(fù)擺動(dòng)

改造服務(wù)

如果你的服務(wù)無(wú)法提供 http 的健康檢查接口,可能需要修改你的業(yè)務(wù)代碼:如 grpc 服務(wù),后面會(huì)提到

image

sidecar 形式做健康檢查

如果你不想更改你的業(yè)務(wù)邏輯,您的應(yīng)用程序容器優(yōu)沒(méi)有公開(kāi)HTTP接口以進(jìn)行健康檢查,那么您可以將另一個(gè)容器部署在pod內(nèi)并調(diào)用您的應(yīng)用程序的,即sidecar模式

image

之所以可行,是因?yàn)镻od的所有容器都在同一個(gè)環(huán)回接口(localhost)中。您無(wú)需將此端口暴露給外界。

Cli 工具

image

你的應(yīng)用雖然不提供端點(diǎn),但是可以通過(guò)exec 的方式執(zhí)行容器內(nèi)預(yù)裝的 cli 工具來(lái)實(shí)現(xiàn)健康檢查,其實(shí)就是腳本形式,變相的 exec

系統(tǒng)探針

image

你的應(yīng)用不提供端點(diǎn),但是可以側(cè)面顯示應(yīng)用的使用狀態(tài),如 cpu內(nèi)存使用率,通過(guò)系統(tǒng)指標(biāo)來(lái)側(cè)面反映服務(wù)的狀態(tài),如機(jī)器學(xué)習(xí)作業(yè)會(huì)使GPU升溫,從而導(dǎo)致計(jì)算速度變慢。檢測(cè)不通過(guò),將作業(yè)移到其他節(jié)點(diǎn)可以解決此問(wèn)題。

如何支持 gprc 的健康檢查

GRPC正在成為云原生微服務(wù)之間通信的通用語(yǔ)言。如果您今天要將gRPC應(yīng)用程序部署到Kubernetes,您可能想知道配置運(yùn)行狀況檢查的最佳方法。在本文中,我們將討論grpc-health-probe,一種Kubernetes本地健康檢查gRPC應(yīng)用程序的方法。

kubernetes本身不支持gRPC健康檢查。這使得gRPC開(kāi)發(fā)人員在部署到Kubernetes時(shí)有以下三種方法:

image
  • httpGet probe: 不能與gRPC原生使用。您需要重構(gòu)您的應(yīng)用程序以同時(shí)提供gRPC和HTTP / 1.1協(xié)議(在不同的端口號(hào)上)。
  • tcpSocket probe: 打開(kāi)套接字到gRPC服務(wù)器是沒(méi)有意義的,因?yàn)樗鼰o(wú)法讀取響應(yīng)正文。
  • exec probe: 這會(huì)定期調(diào)用容器生態(tài)系統(tǒng)中的程序。對(duì)于gRPC,這意味著您自己實(shí)現(xiàn)健康RPC,然后使用編寫(xiě)客戶(hù)端工具,并將客戶(hù)端工具與容器打包到一起。

為了標(biāo)準(zhǔn)化上面提到的“exec探針”方法,我們需要:

  • 標(biāo)準(zhǔn)的健康檢查“協(xié)議”,可以輕松地在任何gRPC服務(wù)器中實(shí)現(xiàn)。
  • 標(biāo)準(zhǔn)的健康檢查“工具”,可以輕松查詢(xún)健康協(xié)議。

得慶幸的是,gRPC有一個(gè)標(biāo)準(zhǔn)的健康檢查協(xié)議。它可以從任何語(yǔ)言輕松使用。生成的代碼和用于設(shè)置運(yùn)行狀況的實(shí)用程序幾乎都在gRPC的所有語(yǔ)言實(shí)現(xiàn)中提供。

如果在gRPC應(yīng)用程序中實(shí)現(xiàn)此運(yùn)行狀況檢查協(xié)議,則可以使用標(biāo)準(zhǔn)/通用工具調(diào)用此Check()方法來(lái)確定服務(wù)器狀態(tài)。

下面你需要的是“標(biāo)準(zhǔn)工具”,它是grpc-health-probe。

image

使用此工具,您可以在所有g(shù)RPC應(yīng)用程序中使用相同的運(yùn)行狀況檢查配置。這種方法需要你:

  • 選擇您喜歡的語(yǔ)言找到gRPC“health”模塊并開(kāi)始使用它(例如Go庫(kù))。
  • 將grpc_health_probe二進(jìn)制文件打到容器中。
  • 配置Kubernetes“exec”探針以調(diào)用容器中的“grpc_health_probe”工具。

或者參考:https://github.com/americanexpress/grpc-k8s-health-check

參考

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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