概述
健康檢查(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í)例
- 多種類型探針檢測(cè)鹅搪,保證異常pod不接入流量
- 不停機(jī)部署,更安全的滾動(dòng)升級(jí)
目前支持的探測(cè)方式包括:
- HTTP
- TCP
- Exec命令
k8s 中的 示例配置如下:
探針類型
默認(rèn)機(jī)制:
如果把 k8s 對(duì) pod 的crash 狀態(tài)判斷也能稱之為“健康檢查”的話遭铺,那算是默認(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)私杜,而是用戶自定義探測(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è):
探測(cè)的方法是:通過(guò) cat 命令檢查 /tmp/healthy 文件是否存在瓢捉。如果命令執(zhí)行成功频丘,返回值為0,Kubernetes 則認(rèn)為本次 Liveness 探測(cè)成功泡态;如果命令返回值非0搂漠,本次 Liveness 探測(cè)失敗。
initialDelaySeconds: 10某弦,指定容器啟動(dòng) 10s 之后開始執(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怔毛。
periodSeconds: 5, 指定每 5 秒執(zhí)行一次 Liveness 探測(cè)亮钦。Kubernetes 如果連續(xù)執(zhí)行 3 次 Liveness 探測(cè)均失敗馆截,則會(huì)殺掉并重啟容器。3次是可以配置的蜂莉,參數(shù)為failureThreshold蜡娶,含義后面解釋
使用上面的 yaml 創(chuàng)建 pod:
剛開始的 30s,健康檢查能通過(guò)映穗。
此時(shí)的events 顯示正常
30s 后窖张,日志會(huì)顯示 /tmp/healthy 已經(jīng)不存在,Liveness 探測(cè)失敗蚁滋。再過(guò)幾十秒宿接,幾次探測(cè)都失敗后赘淮,容器會(huì)被重啟。events 中可以看到重試 了 3次探測(cè)睦霎,每次間隔 10s梢卸,單次探測(cè)的超時(shí)時(shí)間為 1s。
liveness 的配置來(lái)自 v1中的Probe資源副女,所有屬性含義如下:
- httpGet:對(duì)應(yīng)HTTPGetAction對(duì)象蛤高,屬性包括:host、httpHeaders碑幅、path戴陡、port、scheme
- initialDelaySeconds:容器啟動(dòng)后開始探測(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ō)明:
探針執(zhí)行方式
HTTP
HTTP探針可能是最常見的自定義Liveness探針類型嚷辅。 即使您的應(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í)憔涉,此類型的探針則很有用,但是必須是運(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
最后一種類型的探針是TCP探針,Kubernetes嘗試在指定端口上建立TCP連接衩侥。 如果它可以建立連接国旷,則容器被認(rèn)為是健康的;否則被認(rèn)為是不健康的茫死。
如果您有HTTP探針或Command探針不能正常工作的情況跪但,TCP探測(cè)器會(huì)派上用場(chǎng)。 例如峦萎,gRPC或FTP服務(wù)是此類探測(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探針開始失敗筛欢,Kubernetes將停止向該容器發(fā)送流量,直到它通過(guò)唇聘。 判斷容器是否處于可用Ready狀態(tài), 達(dá)到ready狀態(tài)表示pod可以接受請(qǐng)求, 如果不健康版姑, 從service的后端endpoint列表中把pod隔離出去
用戶通過(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)圖示例:
兩種探針對(duì)比
Liveness 探測(cè)和 Readiness 探測(cè)是兩種 Health Check 機(jī)制夫凸,如果不特意配置浑劳,Kubernetes 將對(duì)兩種探測(cè)采取相同的默認(rèn)行為,即通過(guò)判斷容器啟動(dòng)進(jìn)程的返回值是否為零來(lái)判斷探測(cè)是否成功夭拌。
兩種探測(cè)的配置方法完全一樣魔熏,支持的配置參數(shù)也一樣。不同之處在于探測(cè)失敗后的行為:Liveness 探測(cè)是重啟容器鸽扁;Readiness 探測(cè)則是將容器設(shè)置為不可用蒜绽,不接收 Service 轉(zhuǎn)發(fā)的請(qǐng)求。
Liveness 探測(cè)和 Readiness 探測(cè)是獨(dú)立執(zhí)行的桶现,二者之間沒(méi)有依賴躲雅,所以可以單獨(dú)使用,也可以同時(shí)使用骡和。
用 Liveness 探測(cè)判斷容器是否需要重啟以實(shí)現(xiàn)自愈相赁;用 Readiness 探測(cè)判斷容器是否已經(jīng)準(zhǔn)備好對(duì)外提供服務(wù)。Readiness可用于指定容器啟動(dòng)后慰于,判斷容器各服務(wù)是否已正常啟動(dòng)(如啟動(dòng)腳本執(zhí)行后寫指定內(nèi)容至特定文件)
使用場(chǎng)景
擴(kuò)縮容
對(duì)于生產(chǎn)環(huán)境中重要的應(yīng)用都建議配置 Health Check钮科,保證處理客戶請(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)自己的判斷邏輯休里,比如檢查所依賴的數(shù)據(jù)庫(kù)是否就緒桨嫁,示例代碼如下:
健康檢查的步驟為:
- 容器啟動(dòng) 10 秒之后開始探測(cè)。
- 如果 http://[container_ip]:8080/healthy 返回代碼不是 200-400份帐,表示容器沒(méi)有就緒,不接收 Service web-svc 的請(qǐng)求楣导。
- 每隔 5 秒再探測(cè)一次废境。
- 直到返回代碼為 200-400,表明容器已經(jīng)就緒筒繁,然后將其加入到 web-svc 的負(fù)責(zé)均衡中噩凹,開始處理客戶請(qǐng)求。
- 探測(cè)會(huì)繼續(xù)以 5 秒的間隔執(zhí)行毡咏,如果連續(xù)發(fā)生 3 次失敗驮宴,容器又會(huì)從負(fù)載均衡中移除,直到下次探測(cè)成功重新加入呕缭。
滾動(dòng)更新
現(xiàn)有一個(gè)正常運(yùn)行的多副本應(yīng)用堵泽,接下來(lái)對(duì)應(yīng)用進(jìn)行更新(比如使用更高版本的 image)修己,Kubernetes 會(huì)啟動(dòng)新副本,然后發(fā)生了如下事件:
- 正常情況下新副本需要 10 秒鐘完成準(zhǔn)備工作迎罗,在此之前無(wú)法響應(yīng)業(yè)務(wù)請(qǐng)求睬愤。
- 但由于人為配置錯(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 才開始支持startupProbe這個(gè)特性
最佳實(shí)踐
上述的擴(kuò)縮容和滾動(dòng)升級(jí)場(chǎng)景都需要用戶對(duì)應(yīng)用的健康檢查足夠了解,并且配置合適的策略信粮。主要工作是:
- 給用戶程序開發(fā)一個(gè)/healthy 接口黔攒,來(lái)獲取世界可用狀態(tài)(僅僅是 http服務(wù))
- 定義合理的健康檢查組合
注意事項(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ì)提到
sidecar 形式做健康檢查
如果你不想更改你的業(yè)務(wù)邏輯访娶,您的應(yīng)用程序容器優(yōu)沒(méi)有公開HTTP接口以進(jìn)行健康檢查,那么您可以將另一個(gè)容器部署在pod內(nèi)并調(diào)用您的應(yīng)用程序的觉阅,即sidecar模式
之所以可行崖疤,是因?yàn)镻od的所有容器都在同一個(gè)環(huán)回接口(localhost)中。您無(wú)需將此端口暴露給外界留拾。
Cli 工具
你的應(yīng)用雖然不提供端點(diǎn)戳晌,但是可以通過(guò)exec 的方式執(zhí)行容器內(nèi)預(yù)裝的 cli 工具來(lái)實(shí)現(xiàn)健康檢查,其實(shí)就是腳本形式痴柔,變相的 exec
系統(tǒng)探針
你的應(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開發(fā)人員在部署到Kubernetes時(shí)有以下三種方法:
- httpGet probe: 不能與gRPC原生使用震檩。您需要重構(gòu)您的應(yīng)用程序以同時(shí)提供gRPC和HTTP / 1.1協(xié)議(在不同的端口號(hào)上)。
- tcpSocket probe: 打開套接字到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迂猴,然后使用編寫客戶端工具,并將客戶端工具與容器打包到一起背伴。
為了標(biāo)準(zhǔn)化上面提到的“exec探針”方法沸毁,我們需要:
- 標(biāo)準(zhǔn)的健康檢查“協(xié)議”儡率,可以輕松地在任何gRPC服務(wù)器中實(shí)現(xiàn)。
- 標(biāo)準(zhǔ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凛虽。
使用此工具,您可以在所有g(shù)RPC應(yīng)用程序中使用相同的運(yùn)行狀況檢查配置广恢。這種方法需要你:
- 選擇您喜歡的語(yǔ)言找到gRPC“health”模塊并開始使用它(例如Go庫(kù))凯旋。
- 將grpc_health_probe二進(jìn)制文件打到容器中。
- 配置Kubernetes“exec”探針以調(diào)用容器中的“grpc_health_probe”工具钉迷。
或者參考:https://github.com/americanexpress/grpc-k8s-health-check
參考
- https://www.youtube.com/watch?v=mxEvAPQRwhw
- https://cloud.google.com/blog/products/gcp/kubernetes-best-practices-setting-up-health-checks-with-readiness-and-liveness-probes
- https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/#execaction-v1-core
- https://xuxinkun.github.io/2019/10/28/liveness-readiness/
- https://yq.aliyun.com/articles/68567
- https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
- https://www.ianlewis.org/en/kubernetes-health-checks-django
- https://ahmet.im/blog/advanced-kubernetes-health-checks/